/*!
 * LMV v6.4.1
 * 
 * Copyright 2019 Autodesk, Inc.
 * All rights reserved.
 * 
 * This computer source code and related instructions and comments are the
 * unpublished confidential and proprietary information of Autodesk, Inc.
 * and are protected under Federal copyright and state trade secret law.
 * They may not be disclosed to, copied or used by any third party without
 * the prior written consent of Autodesk, Inc.
 * 
 * Autodesk Forge Viewer Usage Limitations:
 * 
 * The Autodesk Forge viewer can only be used to view files generated by
 * Autodesk Forge services. The Autodesk Forge Viewer JavaScript must be
 * delivered from an Autodesk hosted URL.
 */
Autodesk.Extensions.AEC =
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./extensions/AEC/LibraryExports.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./extensions/AEC/CanvasBookmark/CanvasBookmark.css":
/*!**********************************************************!*\
  !*** ./extensions/AEC/CanvasBookmark/CanvasBookmark.css ***!
  \**********************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {


var content = __webpack_require__(/*! !../../../node_modules/css-loader!./CanvasBookmark.css */ "./node_modules/css-loader/index.js!./extensions/AEC/CanvasBookmark/CanvasBookmark.css");

if(typeof content === 'string') content = [[module.i, content, '']];

var transform;
var insertInto;



var options = {"hmr":true}

options.transform = transform
options.insertInto = undefined;

var update = __webpack_require__(/*! ../../../node_modules/style-loader/lib/addStyles.js */ "./node_modules/style-loader/lib/addStyles.js")(content, options);

if(content.locals) module.exports = content.locals;

if(false) {}

/***/ }),

/***/ "./extensions/AEC/CanvasBookmark/CanvasBookmark.js":
/*!*********************************************************!*\
  !*** ./extensions/AEC/CanvasBookmark/CanvasBookmark.js ***!
  \*********************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return CanvasBookmarkExtension; });
/* harmony import */ var _CanvasBookmarkIcons_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./CanvasBookmarkIcons.js */ "./extensions/AEC/CanvasBookmark/CanvasBookmarkIcons.js");
/* harmony import */ var _CreateFrustumShape_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./CreateFrustumShape.js */ "./extensions/AEC/CanvasBookmark/CreateFrustumShape.js");
/* harmony import */ var _HCluster_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./HCluster.js */ "./extensions/AEC/CanvasBookmark/HCluster.js");
function _typeof(obj) {if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {_typeof = function _typeof(obj) {return typeof obj;};} else {_typeof = function _typeof(obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};}return _typeof(obj);}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}function _possibleConstructorReturn(self, call) {if (call && (_typeof(call) === "object" || typeof call === "function")) {return call;}return _assertThisInitialized(self);}function _getPrototypeOf(o) {_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {return o.__proto__ || Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function");}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } });if (superClass) _setPrototypeOf(subClass, superClass);}function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);}function _assertThisInitialized(self) {if (self === void 0) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}

var av = Autodesk.Viewing,avp = av.Private,avu = Autodesk.Viewing.UI;
var namespace = AutodeskNamespace('Autodesk.AEC');
var myExtensionName = 'Autodesk.AEC.CanvasBookmarkExtension';

var LEVEL_EXT = 'Autodesk.AEC.LevelsExtension';





var VISIBILITY_PROP = 'canvasBookmarks';

// Name of the overlay scene that we use graphics overlays (frustum shapes)
var OverlayName = 'CanvasBookmark_Extension_Overlay';
var CutPlaneSetName = 'CanvasBookmark_CutPlanes';


// Returns an array of vector4 values that describe the cutplanes needed to apply a given sectionBox
var box2CutPlanes = function () {
  var normals = [
  new THREE.Vector3(1, 0, 0),
  new THREE.Vector3(0, 1, 0),
  new THREE.Vector3(0, 0, 1),
  new THREE.Vector3(-1, 0, 0),
  new THREE.Vector3(0, -1, 0),
  new THREE.Vector3(0, 0, -1)];


  var plane = new THREE.Plane();

  return function (box, transform) {

    var planeVecs = [];
    for (var i = 0; i < normals.length; i++) {
      plane.normal.copy(normals[i]);
      var onPlane = i < 3 ? box.max : box.min;
      plane.constant = -plane.normal.dot(onPlane);

      if (transform) {
        plane.applyMatrix4(transform);
      }

      planeVecs.push(new THREE.Vector4(plane.normal.x, plane.normal.y, plane.normal.z, plane.constant));
    }
    return planeVecs;
  };
}();

// Interpolate between two given Matrix4 transforms. Note that this requires the transforms
// to be invertible combinations of pos/rotate/scale.
var lerpTransforms = function () {
  var startPos = new THREE.Vector3();
  var endPos = new THREE.Vector3();
  var startScale = new THREE.Vector3();
  var endScale = new THREE.Vector3();
  var startRotate = new THREE.Quaternion();
  var endRotate = new THREE.Quaternion();

  var pos = new THREE.Vector3();
  var scale = new THREE.Vector3();
  var rotate = new THREE.Quaternion();

  return function (startMatrix, endMatrix, t, dstTransform) {
    startMatrix.decompose(startPos, startRotate, startScale);
    endMatrix.decompose(endPos, endRotate, endScale);

    pos.lerpVectors(startPos, endPos, t);
    scale.lerpVectors(startScale, endScale, t);
    THREE.Quaternion.slerp(startRotate, endRotate, rotate, t);

    dstTransform.compose(pos, rotate, scale);

    return dstTransform;
  };
}();

// Interpolates between two bboxes. t is in [0,1]
var lerpBoxes = function lerpBoxes(startBox, endBox, t, dstBox) {
  dstBox.min.lerpVectors(startBox.min, endBox.min, t);
  dstBox.max.lerpVectors(startBox.max, endBox.max, t);
  lerpTransforms(startBox.transform, endBox.transform, t, dstBox.transform);
};

// Clone Box3 with attached transform
var cloneBox = function cloneBox(srcBox) {
  var box = srcBox.clone();
  box.transform = srcBox.transform ? srcBox.transform.clone() : new THREE.Matrix4();
  return box;
};

var setButtonVisible = function setButtonVisible(button, value) {
  requestAnimationFrame(function () {
    if (value) {
      button.container.classList.add('visible');
    } else
    {
      button.container.classList.remove('visible');
    }
  });
};var


CanvasBookmarkExtension = /*#__PURE__*/function (_av$Extension) {_inherits(CanvasBookmarkExtension, _av$Extension);
  function CanvasBookmarkExtension(viewer, options) {var _this;_classCallCheck(this, CanvasBookmarkExtension);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(CanvasBookmarkExtension).call(this, viewer, options));

    _this.viewer = viewer;

    _this.bookmarks = [];
    _this.clusteredBookmarks = [];

    _this.camera = _this.viewer.navigation.getCamera();
    _this.cameraMovedCB = _this.onCameraMoved.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.onVisibilityChangedCB = _this.onVisibilityChanged.bind(_assertThisInitialized(_assertThisInitialized(_this)));

    // SectionBox animations
    _this.sectionBox = null; // SectionBox as defined by currently hovered bookmark (not changed during anims)
    _this.activeSectionBox = null; // Latest applied SectionBox
    _this.animStartSectionBox = null; // Used only during cutplane animations
    _this.animEndSectionBox = null; // Usually equal to this.sectionBox, but this.sectionBox may be null while animEndSectionBox is always valid during an animation
    _this.sectionBoxAnim = null; // AnimControl - only existing during animations

    // bookmarks visibility logic
    _this.changeBookmarksVisibility = _this.changeBookmarksVisibility.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.changeBookmarksVisibilityTimeout = null;

    _this._clusteringEnabled = _this.options.clusterfck !== undefined;
    _this._clusteringThreshold = _this.options.clusteringThreshold || 110; // threshold is (icon_width * 5), depends on "THREE.Vector3.distanceTo()"

    // bookmarks clustering
    if (_this._clusteringEnabled) {
      _this.hcluster = new _HCluster_js__WEBPACK_IMPORTED_MODULE_2__["default"](
      _this.options.clusterfck,
      function (b1, b2) {
        var _b1 = new THREE.Vector2(b1.currentPosProjected.x, b1.currentPosProjected.y);
        var _b2 = new THREE.Vector2(b2.currentPosProjected.x, b2.currentPosProjected.y);
        return _b2.distanceTo(_b1);
      },
      _this._clusteringThreshold);

    }

    _this._filterOutInvisibleBookmark = _this._filterOutInvisibleBookmark.bind(_assertThisInitialized(_assertThisInitialized(_this)));

    _this.levelChangedCB = _this.onLevelChanged.bind(_assertThisInitialized(_assertThisInitialized(_this)));

    _this.extensionLoadedCB = _this.onExtensionLoaded.bind(_assertThisInitialized(_assertThisInitialized(_this)));return _this;
  }_createClass(CanvasBookmarkExtension, [{ key: "setBookmarksVisible", value: function setBookmarksVisible(

    visible) {
      this.bookmarks.forEach(function (b) {return setButtonVisible(b.marker, visible);});
      this.clusteredBookmarks.forEach(function (b) {return setButtonVisible(b.marker, visible);});
      if (!visible) {
        this.stopGhosting();
      }
    } }, { key: "onVisibilityChanged", value: function onVisibilityChanged(

    visible) {
      this.viewer.prefs.set(VISIBILITY_PROP, visible);
      this.setBookmarksVisible(visible);

      if (visible) {
        this.updateBookmarkPositions();
      }
    } }, { key: "isVisible", value: function isVisible()

    {
      return this.viewer.prefs.get(VISIBILITY_PROP);
    } }, { key: "onCameraMoved", value: function onCameraMoved()

    {
      this.setBookmarksVisible(false);
      this.debounceBookmarksVisibility();
    } }, { key: "createTooltip", value: function createTooltip(

    button, geomNode) {
      button.setToolTip(geomNode.name());
      button._toolTipElement.innerHTML = "<b>".concat(geomNode.name(), "</b>");
    } }, { key: "flyToBookmark", value: function flyToBookmark(

    bookmark) {
      var dstView = {
        position: bookmark.pos,
        target: bookmark.target,
        up: bookmark.up };

      this.anim = avp.flyToView(this.viewer, dstView, 1.0);
    }

    // geomNode is a BubbleNode of type GEOMETRY_NODE
  }, { key: "createBookmark", value: function createBookmark(geomNode) {var _this2 = this;

      // extract camera data (TODO: Add generic utility function to BubbleNode to read camera)
      var camera = geomNode.extractCamera();
      if (!camera) {
        return;
      }

      var pos = camera.position;
      var target = camera.target;

      // Consider refPointTransform:
      //    cameras are in local Revit coordinates. To support georeferencing, we apply the refPointTransform
      //    from aecModelData and finally subtract the viewer geoOffset
      var root = geomNode.getRootNode();
      var tfMatrix = root.extractRefPointTransform();

      if (this.options.globalOffset && tfMatrix) {

        // apply refPointTransform and globalOffset to pos and target
        pos.applyMatrix4(tfMatrix);
        pos.sub(this.options.globalOffset);
        target.applyMatrix4(tfMatrix);
        target.sub(this.options.globalOffset);
      }

      var dir = new THREE.Vector3(target.x - pos.x, target.y - pos.y, target.z - pos.z).normalize();
      var up = new THREE.Vector3(0, 0, 1);

      // IDs cannot start with numbers and have whitespaces
      var button = new Autodesk.Viewing.UI.Button("b-".concat(geomNode.name().replace(/\s/g, '')));

      // Configure style (TODO: Should move to css class or specified by client app)
      button.container.classList.add('canvas-bookmark');
      button.container.innerHTML = Object(_CanvasBookmarkIcons_js__WEBPACK_IMPORTED_MODULE_0__["createCameraIcon"])();
      setButtonVisible(button, this.isVisible());

      this.createTooltip(button, geomNode);

      this.viewer.container.appendChild(button.container);

      var buttonSize = button.getDimensions();

      var sectionBox = this.findSectionBox(geomNode, geomNode.name());
      var sectionBoxCenter = sectionBox ? sectionBox.center().applyMatrix4(sectionBox.transform) : null;

      var bookmark = {
        marker: button,
        pos: sectionBox ? sectionBoxCenter : pos,
        cameraPos: pos,
        dir: dir,
        up: up,
        target: target,
        name: geomNode.name(),

        // position within the marker that should be centered
        anchorX: buttonSize.width / 2,
        anchorY: buttonSize.height / 2,

        fadeValue: 0.0,
        hovered: false,
        bubbleNode: geomNode,

        clustered: false };


      button.container.addEventListener('mouseenter', function () {_this2.onBookmarkMouseEnter(bookmark);});
      button.container.addEventListener('mouseleave', function () {_this2.onBookmarkMouseLeave(bookmark);});

      button.addEventListener(avu.Button.Event.CLICK, function () {
        // pass to custom handler
        if (_this2.options && _this2.options.onBookmark) {
          _this2.options.onBookmark(bookmark.bubbleNode, camera);
        }
      });

      return bookmark;
    } }, { key: "createClusteredBookmark", value: function createClusteredBookmark(

    flattenCluster, id, visible) {var _this3 = this;
      var button = new Autodesk.Viewing.UI.Button(id);

      button.container.classList.add('clustered-canvas-bookmark');
      button.container.innerHTML = Object(_CanvasBookmarkIcons_js__WEBPACK_IMPORTED_MODULE_0__["createClusteredCameraIcon"])();

      setButtonVisible(button, this.isVisible() && visible);

      this.viewer.container.appendChild(button.container);

      var res = _HCluster_js__WEBPACK_IMPORTED_MODULE_2__["default"].ComputeMeanValueForFlattenCluster(flattenCluster);

      var bookmark = {
        marker: button,
        name: id,

        pos: res.center3D,
        currentPosProjected: res.center2D,

        cluster: flattenCluster,

        fadeValue: 0.0,
        hovered: false,

        folded: true };


      button.container.addEventListener('mouseenter', function () {_this3.onClusteredBookmarkMouseEnter(bookmark);});
      button.container.addEventListener('mouseleave', function () {_this3.onClusteredBookmarkMouseLeave(bookmark);});
      button.addEventListener(avu.Button.Event.CLICK, function () {_this3.onClusteredBookmarkClicked(bookmark);});

      bookmark.marker.container.style.transform = "translate(".concat(res.center2D.x, "px, ").concat(res.center2D.y, "px)");
      this.clusteredBookmarks.push(bookmark);
    } }, { key: "deleteBookmark", value: function deleteBookmark(

    bookmark) {
      this.viewer.container.removeChild(bookmark.marker.container);
      this.hideFrustumShape(bookmark);
    } }, { key: "clearBookmarks", value: function clearBookmarks()

    {var _this4 = this;
      // Cancel any outdated anims or cutplanes
      this.stopSectionBoxAnim();
      this.applySectionBox();

      this.bookmarks.forEach(function (bm) {
        _this4.deleteBookmark(bm);
      });
      this.bookmarks = [];

      this.clusteredBookmarks.forEach(function (bm) {
        _this4.deleteBookmark(bm);
      });
      this.clusteredBookmarks = [];
    } }, { key: "resetBookmarks", value: function resetBookmarks(

    geomNodes) {
      this.clearBookmarks();
      if (!geomNodes) {
        return;
      }

      for (var i = 0; i < geomNodes.length; i++) {
        var geomNode = geomNodes[i];
        var bookmark = this.createBookmark(geomNode);
        if (bookmark) {
          this.bookmarks.push(bookmark);
        }
      }

      this.bookmarkData = geomNodes;

      this.updateBookmarkPositions();
    }

    // Create bookmarks with correct positions for the current geoOffset
  }, { key: "resetGlobalOffset", value: function resetGlobalOffset(globalOffset) {
      this.options.globalOffset = globalOffset;
      this.resetBookmarks(this.bookmarkData);
    } }, { key: "showFrustumShape", value: function showFrustumShape(

    bookmark) {
      if (bookmark.frustumShape) {
        return;
      }

      bookmark.frustumShape = Object(_CreateFrustumShape_js__WEBPACK_IMPORTED_MODULE_1__["createFrustumShape"])(bookmark.cameraPos, bookmark.dir);
      this.viewer.impl.addOverlay(OverlayName, bookmark.frustumShape);

      bookmark.frustumShape.name = bookmark.bubbleNode.name();

      // Make LMV recompute near/far plane, so that the frustum shape is considered
      // TODO: It would be easier if LMV would do that automatically, but it
      //       updates the camera only when rendering the scene.
      //       => Clarify if we can generally change that.
      this.viewer.impl.updateCameraMatrices();
    } }, { key: "hideFrustumShape", value: function hideFrustumShape(

    bookmark) {
      if (!bookmark.frustumShape) {
        return;
      }

      this.viewer.impl.removeOverlay(OverlayName, bookmark.frustumShape);
      bookmark.frustumShape = null;
    }

    // Controls the frustum fading. fadeValue is in [0,1]
  }, { key: "setFrustumFadeValue", value: function setFrustumFadeValue(bookmark, fadeValue) {
      bookmark.fadeValue = fadeValue;
      if (bookmark.frustumShape) {
        bookmark.frustumShape.setFadeValue(fadeValue);
      }
    }

    // Update fading of the frustum shape based on elpased time in ms.
  }, { key: "updateFrustumShapeFading", value: function updateFrustumShapeFading(bookmark, elapsed) {
      var FadeInDurationMs = 500;
      var FadeOutDurationMs = 500;

      var fadingIn = bookmark.hovered && bookmark.fadeValue < 1.0;
      var fadingOut = !bookmark.hovered && bookmark.fadeValue > 0.0;

      if (!fadingIn && !fadingOut) {
        return;
      }

      // compute amount of fading change (1.0 = full fade)
      var fadeInDelta = elapsed / FadeInDurationMs;
      var fadeOutDelta = elapsed / FadeOutDurationMs;
      var newValue = bookmark.fadeValue + (fadingIn ? fadeInDelta : -fadeOutDelta);

      newValue = THREE.Math.clamp(newValue, 0, 1);
      this.setFrustumFadeValue(bookmark, newValue);

      // HACK: Use css fade instead
      if (bookmark.marker && bookmark.marker._toolTipElement) {
        bookmark.marker._toolTipElement.style.opacity = Math.min(1, 3 * newValue);
      }

      // remove frustums if not used anymore
      if (!bookmark.hovered && bookmark.fadeValue === 0) {
        this.hideFrustumShape(bookmark);
      }

      this.viewer.impl.invalidate(false, false, true);
    } }, { key: "requestTimer", value: function requestTimer()

    {var _this5 = this;
      this.timerId = window.requestAnimationFrame(function () {return _this5.onTimer();});
    } }, { key: "onTimer", value: function onTimer()

    {var _this6 = this;
      // get elapsed time in ms
      var curTime = performance.now();
      var elapsed = curTime - this.lastTime;
      this.lastTime = curTime;

      this.bookmarks.forEach(function (bookmark) {
        _this6.updateFrustumShapeFading(bookmark, elapsed);
      });

      this.requestTimer();
    }

    // Returns an oriented box (THREE.Box3() + attached Matrix4 box.transform)
  }, { key: "findSectionBox", value: function findSectionBox(bubbleNode, name) {
      var viewNode = bubbleNode.search({ type: 'view' });

      if (!viewNode.length || viewNode[0].data.name !== name)
      return null;

      var sb = viewNode[0].data.sectionBox;
      var sbt = viewNode[0].data.sectionBoxTransform;

      if (!sb || !sbt)
      return null;

      var sbTransformMatrix = new THREE.Matrix4().fromArray([
      sbt[0], sbt[1], sbt[2], sbt[3],
      sbt[4], sbt[5], sbt[6], sbt[7],
      sbt[8], sbt[9], sbt[10], sbt[11],
      sbt[12], sbt[13], sbt[14], sbt[15]]);


      var box = new THREE.Box3();
      box.min.set(sb[0], sb[1], sb[2]);
      box.max.set(sb[3], sb[4], sb[5]);
      box.transform = new THREE.Matrix4();

      var tf = bubbleNode.getRootNode().getAecModelData().refPointTransformation;
      if (this.options.globalOffset && tf) {
        var offset = this.options.globalOffset;

        var geoTransformMatrix = av.BubbleNode.readMatrixFromArray12(tf);

        // Apply sectionBox rotation (if any), geoRefTransform, and finally the viewer offset.
        // Note that matrices must be multiplied in reverse order.
        box.transform.makeTranslation(-offset.x, -offset.y, -offset.z);
        box.transform.multiply(geoTransformMatrix);
        box.transform.multiply(sbTransformMatrix);
      }

      return box;
    }

    // The overlay scene contains the frustum shapes and is always visible by default. We only hide it temporarily
    // when baking an image for showin ghost floors
  }, { key: "setOverlaySceneVisible", value: function setOverlaySceneVisible(visible) {
      // Overlay may be null if this is currently unloaded
      var overlay = this.viewer.impl.overlayScenes[OverlayName];
      var scene = overlay && overlay.scene;
      if (scene) {
        scene.visible = visible;
      }
    } }, { key: "getFadeExtension", value: function getFadeExtension()

    {
      return this.viewer.getExtension('Autodesk.CrossFadeEffects');
    }

    // Render models without SectionBox into fading target
  }, { key: "showGhosting", value: function showGhosting() {var _this7 = this;
      // Ghosting is an optional effect that requires the CrossFade extension. If we don't have it,
      // we omit ghosting, i.e., only apply the cutplanes for SectionBox previous.
      var fadeExt = this.getFadeExtension();
      if (!fadeExt) {
        return;
      }

      // Take control over CrossFade effect. Purpose is to avoid conflicts with other effects based on CrossFade. E.g., if we are
      // still showing ghost-floors from LevelsExtension, LevelsExtension will properly clean them up first.
      fadeExt.acquireControl('CanvasBookmarks', function () {return _this7.stopGhosting();});

      // If possible, reuse baked ghosting image from previous bookmark
      if (!this.ghostingActive) {
        this.viewer.impl.setCutPlaneSet(CutPlaneSetName); // disable current SectionBox
        this.setOverlaySceneVisible(false); // make sure that we don't bake Frustum shapes into the screenshot
        fadeExt.renderFadingImage(0); // render snapshot into fading target
        this.applySectionBox(this.activeSectionBox); // recover current SectionBox
        this.setOverlaySceneVisible(true); // show overlay scene again (We don't hide it anywhere else, otherwise we would need to save/restore visibility state)
        this.ghostingActive = true;
      } else {
        // Reuse ghosting from before - just make sure that no fadeOut anim is in-progress
        this.stopGhostFadeOut();
      }
      fadeExt.setCrossFadeOpacity(0, 0.3); // overlay full model with ghost opacity
    } }, { key: "stopGhosting", value: function stopGhosting()

    {
      if (this.ghostingActive) {
        this.stopGhostFadeOut();
        var fadeExt = this.getFadeExtension();
        fadeExt && fadeExt.releaseFadingImage(0);
        this.ghostingActive = false;
      }
    } }, { key: "stopGhostFadeOut", value: function stopGhostFadeOut()

    {
      // skip fade-out animation if in progress
      if (this.ghostFadeAnim) {
        this.ghostFadeAnim.skip();
        this.ghostFadeAnim = null;
      }
    }

    // Fade-out cross-fade target containing the ghosted environment
  }, { key: "fadeOutGhosting", value: function fadeOutGhosting() {
      var fadeExt = this.getFadeExtension();
      if (!this.ghostingActive || !fadeExt) {
        // No ghosting active => nothing to do
        return;
      }

      var ghostAlpha = fadeExt.getCrossFadeOpacity(0);
      this.ghostFadeAnim = avp.fadeValue(ghostAlpha, 0.0, 0.5, function (t) {return fadeExt.setCrossFadeOpacity(0, t);});
    } }, { key: "onBookmarkMouseEnter", value: function onBookmarkMouseEnter(

    bookmark) {
      var sectionBox = this.findSectionBox(bookmark.bubbleNode, bookmark.name);
      if (sectionBox) {
        this.showGhosting();
        this.animateToSectionBox(sectionBox);
      }

      this.showFrustumShape(bookmark);
      bookmark.hovered = true;
    } }, { key: "onBookmarkMouseLeave", value: function onBookmarkMouseLeave(

    bookmark) {
      this.animateToSectionBox(null);
      this.fadeOutGhosting();
      bookmark.hovered = false;
    } }, { key: "onClusteredBookmarkMouseEnter", value: function onClusteredBookmarkMouseEnter(

    bookmark) {
      bookmark.hovered = true;
    } }, { key: "onClusteredBookmarkMouseLeave", value: function onClusteredBookmarkMouseLeave(

    bookmark) {
      bookmark.hovered = false;
    } }, { key: "onClusteredBookmarkClicked", value: function onClusteredBookmarkClicked(

    bookmark) {
      // TODO:
      //   - Zoom + zoom level computation
      //   - "Too many" clustered bookmarks -> (n+1) icon should be "..."

      if (bookmark.folded) {
        var _rotate = function _rotate(vector, center, angle) {
          var c = Math.cos(angle);
          var s = Math.sin(angle);

          var x = vector.x - center.x;
          var y = vector.y - center.y;

          vector.x = x * c - y * s + center.x;
          vector.y = x * s + y * c + center.y;
        };

        var n = bookmark.cluster.length;
        var alpha = Math.round(360.0 / n);

        var center = new THREE.Vector2(bookmark.currentPosProjected.x, bookmark.currentPosProjected.y);

        var start = new THREE.Vector2(center.x, center.y + 35);

        for (var i = 0; i < n; ++i) {
          var bm = bookmark.cluster[i];

          var current = start.clone();
          _rotate(current, center, i * alpha * Math.PI / 180.0);

          bm.currentPosProjected.x = current.x;
          bm.currentPosProjected.y = current.y;

          bm.marker.container.style.transform = "translate(".concat(current.x, "px, ").concat(current.y, "px)");
          setButtonVisible(bm.marker, true);
        }

        bookmark.marker.container.classList.add('declustered-canvas-bookmark');
      } else
      {
        bookmark.cluster.forEach(function (bm) {
          setButtonVisible(bm.marker, false);
        });

        bookmark.marker.container.classList.remove('declustered-canvas-bookmark');
      }

      bookmark.folded = !bookmark.folded;
    } }, { key: "debounceBookmarksVisibility", value: function debounceBookmarksVisibility()

    {
      if (this.changeBookmarksVisibilityTimeout) {
        clearTimeout(this.changeBookmarksVisibilityTimeout);
      }

      this.changeBookmarksVisibilityTimeout = setTimeout(this.changeBookmarksVisibility, 100);
    } }, { key: "changeBookmarksVisibility", value: function changeBookmarksVisibility()

    {
      this.updateBookmarkPositions();
    } }, { key: "updateBookmarkPositions", value: function updateBookmarkPositions()

    {var _this8 = this;
      if (!this.isVisible()) {
        return;
      }

      this.bookmarks.forEach(function (bookmark) {
        // Use cropBox center (if available) or camera position to choose label position
        var sBox = bookmark.bubbleNode.sectionBox;
        var pos3D = sBox ? sBox.center() : bookmark.pos;

        bookmark.currentPos3D = pos3D;

        // In-canvas coordinates
        var pos2D = _this8.project(pos3D);
        pos2D.x -= bookmark.anchorX;
        pos2D.y -= bookmark.anchorY;

        bookmark.currentPosProjected = new THREE.Vector3(pos2D.x, pos2D.y, pos2D.z);
        bookmark.marker.container.style.transform = "translate(".concat(pos2D.x, "px, ").concat(pos2D.y, "px)");
      });

      var clusters = this._clusteringEnabled ? this.hcluster.createClusters(this.bookmarks) : [];
      this.updateClusteredBookmarks(clusters);
    } }, { key: "updateClusteredBookmarks", value: function updateClusteredBookmarks(

    clusters) {var _this9 = this;
      // delete all "cluster" bookmarks since we create them all the time (by design), hiding will not really work
      this.clusteredBookmarks.forEach(function (bookmark) {
        _this9.deleteBookmark(bookmark);
      });
      this.clusteredBookmarks = [];

      // hide all bookmarks and reset "clustered" state
      this.bookmarks.forEach(function (bookmark) {
        setButtonVisible(bookmark.marker, false);
      });

      var floorSelector = this._getFloorSelector();
      var currentLevel = floorSelector && floorSelector.currentFloor;
      if (currentLevel !== undefined) {
        return;
      }

      var visibleBookamrks = this.bookmarks.filter(this._filterOutInvisibleBookmark);
      visibleBookamrks.forEach(function (bookmark) {
        bookmark.clustered = false;
        setButtonVisible(bookmark.marker, true);
      });

      for (var i = 0; i < clusters.length; i++) {
        var c = clusters[i];

        if (c.size > 1) {(function () {
            var flCluster = _HCluster_js__WEBPACK_IMPORTED_MODULE_2__["default"].FlattenCluster(c);

            var clusterBmVisible = false;
            flCluster.forEach(function (bookmark) {
              bookmark.clustered = true;
              if (!clusterBmVisible && bookmark.marker.isVisible()) {
                // if one of the included bookmarks is visible, mark the cluster bookmark as visible one
                clusterBmVisible = true;
              }
              // now, mark the included bookmark as invisible one
              setButtonVisible(bookmark.marker, false);
            });

            // IDs cannot start with some number
            _this9.createClusteredBookmark(flCluster, "c-".concat(flCluster[0].bubbleNode.data.viewableID), clusterBmVisible);})();
        }
      }
    } }, { key: "project", value: function project(

    position) {
      var containerBounds = this.viewer.navigation.getScreenViewport();
      var p = new THREE.Vector3().copy(position);

      var matrix = new THREE.Matrix4();
      matrix.multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse);

      p.applyProjection(matrix);

      return new THREE.Vector3(
      Math.round((p.x + 1) / 2 * containerBounds.width),
      Math.round((-p.y + 1) / 2 * containerBounds.height),
      p.z);

    } }, { key: "load", value: function load()

    {
      this.viewer.addEventListener(av.CAMERA_CHANGE_EVENT, this.cameraMovedCB);

      var floorSelector = this._getFloorSelector();
      if (floorSelector) {
        floorSelector.addEventListener(Autodesk.AEC.FloorSelector.CURRENT_FLOOR_CHANGED, this.levelChangedCB);
      }

      this.viewer.addEventListener(av.EXTENSION_LOADED_EVENT, this.extensionLoadedCB);

      // handle the case when this extension is loaded after LevelsExtension is loaded,
      // without making this extension known to LevelsExtension
      this.updateBookmarkPositions();

      this.viewer.impl.createOverlayScene(OverlayName);

      // trigger timer-calls for fading animations
      this.lastTime = performance.now();
      this.requestTimer();

      return true;
    } }, { key: "unload", value: function unload()

    {
      this.clearBookmarks();

      this.viewer.impl.removeOverlayScene(OverlayName);

      this.viewer.removeEventListener(av.CAMERA_CHANGE_EVENT, this.cameraMovedCB);

      var floorSelector = this._getFloorSelector();
      if (floorSelector) {
        floorSelector.removeEventListener(Autodesk.AEC.FloorSelector.CURRENT_FLOOR_CHANGED, this.levelChangedCB);
      }

      this.viewer.removeEventListener(av.EXTENSION_LOADED_EVENT, this.extensionLoadedCB);

      // Stop timer for position updates
      if (this.timerId) {
        window.cancelAnimationFrame(this.timerId);
        this.timerId = null;
      }
      return true;
    } }, { key: "applySectionBox", value: function applySectionBox(

    box) {
      this.activeSectionBox = box;

      // No box => clear cutplanes
      if (!box) {
        this.viewer.impl.setCutPlaneSet(CutPlaneSetName);
        return;
      }

      var planes = box2CutPlanes(box, box.transform);
      this.viewer.impl.setCutPlaneSet(CutPlaneSetName, planes);
    }

    // get bbox of all visible models
  }, { key: "getModelBox", value: function getModelBox() {
      var mq = this.viewer.impl.modelQueue();
      var models = mq.getModels();

      var box = new THREE.Box3();
      for (var i = 0; i < models.length; i++) {
        box.union(models[i].getBoundingBox());
      }

      return box;
    } }, { key: "stopSectionBoxAnim", value: function stopSectionBoxAnim()

    {
      if (this.sectionBoxAnim) {
        this.sectionBoxAnim.stop();
        this.sectionBoxAnim = null;
      }
    } }, { key: "animateToSectionBox", value: function animateToSectionBox(

    newBox) {var _this10 = this;
      // Nothing to animate
      if (!newBox && !this.activeSectionBox) {
        return;
      }

      // Don't allow overlapping animations
      this.stopSectionBoxAnim();

      var CutPlaneAnimInSeconds = 0.5;

      // Start at latest SectionBox state or with the whole model
      this.animStartBox = this.activeSectionBox ? cloneBox(this.activeSectionBox) : cloneBox(this.getModelBox());
      this.animEndBox = newBox ? cloneBox(newBox) : cloneBox(this.getModelBox());

      // Set target box
      this.sectionBox = newBox;

      // interpolated box used during anim
      var tmpBox = new THREE.Box3();
      tmpBox.transform = new THREE.Matrix4();

      var onUpdate = function onUpdate(t) {
        t = avp.smootherStep(t);
        lerpBoxes(_this10.animStartBox, _this10.animEndBox, t, tmpBox);
        _this10.applySectionBox(tmpBox);
      };

      var onFinished = function onFinished() {
        _this10.applySectionBox(_this10.sectionBox);
        _this10.sectionBoxAnim = null;
      };

      this.sectionBoxAnim = avp.fadeValue(0, 1, CutPlaneAnimInSeconds, onUpdate, onFinished);
    } }, { key: "enableClustering", value: function enableClustering(

    value) {
      if (this._clusteringEnabled !== value) {
        this._clusteringEnabled = value;
        this.updateClusteredBookmarks([]);
      }
    } }, { key: "setClusteringThreshold", value: function setClusteringThreshold(

    value) {
      if (this._clusteringThreshold !== value) {
        this._clusteringThreshold = value;
        this.hcluster.setThreshold(value);
        this.updateClusteredBookmarks([]);
      }
    } }, { key: "_filterOutInvisibleBookmark", value: function _filterOutInvisibleBookmark(

    bm) {
      var vp = this.viewer.navigation.getScreenViewport();

      if (bm.currentPosProjected.x < 0 || bm.currentPosProjected.x > vp.width) {
        return false;
      }

      if (bm.currentPosProjected.y < 0 || bm.currentPosProjected.y > vp.height) {
        return false;
      }

      var viewingDirection = this.camera.target.clone().sub(this.camera.position);
      var bookmarkDirection = bm.pos.clone().sub(this.camera.position);
      return viewingDirection.dot(bookmarkDirection) > 0;
    } }, { key: "onLevelChanged", value: function onLevelChanged()

    /*event*/{
      this.updateBookmarkPositions();
    } }, { key: "onExtensionLoaded", value: function onExtensionLoaded(

    event) {
      if (event.extensionId === LEVEL_EXT) {
        this.updateBookmarkPositions();
      }
    } }, { key: "updateSettings", value: function updateSettings(

    panel, tab) {
      // add toggle to the hypermodeling tab of the viewer settings
      if (panel && !panel.showLocationIconsChkBoxId) {
        panel.showLocationIconsChkBoxId = panel.addCheckbox(
        tab,
        "Show location icons",
        "Toggles availability of the location icons when looking at the project model",
        true,
        this.onVisibilityChangedCB,
        VISIBILITY_PROP);

      }
    } }, { key: "_getFloorSelector", value: function _getFloorSelector()

    {
      var levelExt = this.viewer.getExtension(LEVEL_EXT);
      return levelExt && levelExt.floorSelector;
    } }]);return CanvasBookmarkExtension;}(av.Extension);



namespace.CanvasBookmarkExtension = CanvasBookmarkExtension;

Autodesk.Viewing.theExtensionManager.registerExtension(myExtensionName, CanvasBookmarkExtension);

/***/ }),

/***/ "./extensions/AEC/CanvasBookmark/CanvasBookmarkIcons.js":
/*!**************************************************************!*\
  !*** ./extensions/AEC/CanvasBookmark/CanvasBookmarkIcons.js ***!
  \**************************************************************/
/*! exports provided: createCameraIcon, createClusteredCameraIcon */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createCameraIcon", function() { return createCameraIcon; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createClusteredCameraIcon", function() { return createClusteredCameraIcon; });

function createCameraIcon() {
  return [
  '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 114 114">',
  '<defs>',
  '<path id="camera-view-icon-3-with-shadow-v3-b" d="M60.934065,73.4602645 C54.1164768,73.4602645 48.5886781,67.9324658 48.5886781,61.1148776 C48.5886781,54.2963836 54.1164768,48.7694907 60.934065,48.7694907 C67.752559,48.7694907 73.2803577,54.2963836 73.2803577,61.1148776 C73.2803577,67.9324658 67.752559,73.4602645 60.934065,73.4602645 M78.7230158,42.834104 C77.2575106,42.9581919 75.7711731,42.808743 74.2984219,42.8748628 C73.4714712,42.9119986 72.9388896,42.637556 72.4470667,41.9817922 C70.947143,39.9827997 69.3693246,38.0417751 67.8621549,36.0491228 C67.287003,35.2873862 66.5959149,34.9939228 65.6521223,35.0029804 C62.0046628,35.0355874 58.354486,35.0401161 54.7070265,35.0002631 C53.7097946,34.9893941 53.0033088,35.3145587 52.4046073,36.1116196 C50.9028721,38.1088007 49.382116,40.0951128 47.7852769,42.0171165 C47.4311283,42.4437253 46.748192,42.7707014 46.1884378,42.8187062 C44.8515493,42.9346424 43.4974514,42.855842 41.9640149,42.855842 C41.9640149,42.2091358 41.9929989,41.6520989 41.9576746,41.0995907 C41.8897433,40.036239 41.3046281,39.4293858 40.2331246,39.4112707 C38.5112919,39.381381 36.7894591,39.3759465 35.0676263,39.4130822 C33.9934056,39.4366318 33.4291227,40.057977 33.3892696,41.1303863 C33.3693431,41.6557219 33.3856466,42.1819632 33.3856466,42.8078372 C31.121269,42.9074698 29.8523117,44.2289606 29,46.07941 L29,75.8722796 C30.0434252,78.4165343 31.9636175,79.1737422 34.6482636,79.1583444 C49.3911736,79.0686751 64.1340835,79.0713923 78.8769935,79.1556272 C81.5299383,79.1710249 83.372236,78.3377339 84.4011692,75.8722796 L84.4011692,46.07941 C83.3332887,43.5523646 81.4058504,42.6067605 78.7230158,42.834104"/>',
  '<filter id="camera-view-icon-3-with-shadow-v3-a" width="125.3%" height="131.7%" x="-12.6%" y="-11.3%" filterUnits="objectBoundingBox">',
  '<feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/>',
  '<feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="2"/>',
  '<feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0"/>',
  '</filter>',
  '<path id="camera-view-icon-3-with-shadow-v3-d" d="M104.440851,57.2204256 C104.440851,83.2997158 83.2997158,104.440851 57.2204256,104.440851 C31.1411354,104.440851 10,83.2997158 10,57.2204256 C10,31.1411354 31.1411354,10 57.2204256,10 C83.2997158,10 104.440851,31.1411354 104.440851,57.2204256 Z"/>',
  '<filter id="camera-view-icon-3-with-shadow-v3-c" width="125.5%" height="125.5%" x="-12.8%" y="-10.6%" filterUnits="objectBoundingBox">',
  '<feMorphology in="SourceAlpha" operator="dilate" radius="5.045" result="shadowSpreadOuter1"/>',
  '<feOffset dy="2" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>',
  '<feMorphology in="SourceAlpha" radius="5.045" result="shadowInner"/>',
  '<feOffset dy="2" in="shadowInner" result="shadowInner"/>',
  '<feComposite in="shadowOffsetOuter1" in2="shadowInner" operator="out" result="shadowOffsetOuter1"/>',
  '<feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="2"/>',
  '<feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0"/>',
  '</filter>',
  '</defs>',
  '<g fill="none" fill-rule="evenodd">',
  '<use fill="#000" filter="url(#camera-view-icon-3-with-shadow-v3-a)" xlink:href="#camera-view-icon-3-with-shadow-v3-b"/>',
  '<use fill="currentColor" xlink:href="#camera-view-icon-3-with-shadow-v3-b"/>',
  '<g>',
  '<use fill="#000" filter="url(#camera-view-icon-3-with-shadow-v3-c)" xlink:href="#camera-view-icon-3-with-shadow-v3-d"/>',
  '<use stroke="currentColor" stroke-width="10.09" xlink:href="#camera-view-icon-3-with-shadow-v3-d"/>',
  '</g>',
  '</g>',
  '</svg>'].
  join('');
}

function createClusteredCameraIcon() {
  return [
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 652 598">',
  '<path fill="currentColor" d="M254.7,94.3A157.6,157.6,0,1,0,412.3,251.9,157.6,157.6,0,0,0,254.7,94.3ZM173.6,281.4a24.2,24.2,0,1,1,23.9-24.2A23.8,23.8,0,0,1,173.6,281.4Zm86.6,0a24.2,24.2,0,1,1,23.9-24.2A23.8,23.8,0,0,1,260.2,281.4Zm86.7,0a24.2,24.2,0,1,1,23.9-24.2A23.8,23.8,0,0,1,346.9,281.4Z"/>',
  '<circle fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="42.87px" cx="256" cy="256" r="221.5" transform="translate(-101.8 200.6) rotate(-36.2)"/>',
  '</svg>'].
  join('');
}

/***/ }),

/***/ "./extensions/AEC/CanvasBookmark/CreateFrustumShape.js":
/*!*************************************************************!*\
  !*** ./extensions/AEC/CanvasBookmark/CreateFrustumShape.js ***!
  \*************************************************************/
/*! exports provided: createFrustumShape */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createFrustumShape", function() { return createFrustumShape; });


// Returns a THREE.Scene to represent the camera frustum
function createFrustumShape(pos, dir) {
  // The frustum shape is a symbol to explain pos and dir - not the exact frustum.
  var FovVert = 17;
  var FovHor = 17;

  // Frustum shape/outline opacity when fully faded in
  var FrustumOpacity = 0.05;
  var LineOpacity = 1.0;

  var radians = THREE.Math.degToRad;
  var dx = Math.sin(radians(FovHor));
  var dy = Math.sin(radians(FovVert));

  // compute z in a way that the results are normalized
  var dz = Math.sqrt(1 - dx * dx - dy * dy);

  // compute directions for the 4 frustum-corners
  var bottomLeft = new THREE.Vector3(-dx, -dy, dz);

  var bottomRight = new THREE.Vector3(dx, -dy, dz);
  var topLeft = new THREE.Vector3(-dx, dy, dz);
  var topRight = new THREE.Vector3(dx, dy, dz);

  // create mesh vertices: 4 corners + origin
  var vertices = new Float32Array([
  bottomLeft.x, bottomLeft.y, bottomLeft.z,
  bottomRight.x, bottomRight.y, bottomRight.z,
  topLeft.x, topLeft.y, topLeft.z,
  topRight.x, topRight.y, topRight.z,
  0, 0, 0]);


  var bl = 0;
  var br = 1;
  var tl = 2;
  var tr = 3;
  var p0 = 4; // index of camera position vertex

  var indices = new Uint32Array([
  p0, br, bl, // bottom face
  p0, tr, br, // right face
  p0, tl, tr, // top face
  p0, bl, tl, // left face
  bl, br, tr, // far face lower tri
  bl, tr, tl]);


  // Extract vertices to non-indexed, so that we can compute face-normals
  var vertsNonIndexed = new Float32Array(3 * indices.length);
  for (var i = 0; i < indices.length; i++) {
    var index = indices[i];
    vertsNonIndexed[3 * i] = vertices[3 * index];
    vertsNonIndexed[3 * i + 1] = vertices[3 * index + 1];
    vertsNonIndexed[3 * i + 2] = vertices[3 * index + 2];
  }

  var geometry = new THREE.BufferGeometry();
  geometry.addAttribute('position', new THREE.BufferAttribute(vertsNonIndexed, 3));

  geometry.computeVertexNormals();

  var material = new THREE.MeshPhongMaterial({
    color: 0x5050FF,
    transparent: true,
    opacity: 0.0, // will change with fade-in
    depthTest: false,
    depthWrite: false,
    blending: THREE.NoBlending });


  var mesh = new THREE.Mesh(geometry, material);

  // create frustum lines
  var lineIndices = new Uint32Array([
  p0, bl,
  p0, br,
  p0, tr,
  p0, tl,
  bl, br,
  br, tr,
  tr, tl,
  tl, bl]);


  var lineGeom = new THREE.BufferGeometry();
  lineGeom.addAttribute('index', new THREE.BufferAttribute(lineIndices, 1));
  lineGeom.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
  lineGeom.isLines = true;

  var lineMaterial = new THREE.LineBasicMaterial({
    color: 0xFFFFFF,
    transparent: true,
    side: THREE.DoubleSide,
    opacity: 0.0, // will change with fade-in
    depthTest: false,
    depthWrite: false,
    blending: THREE.NoBlending // NOTE: Overlay target is blended anyway. So, using blend here would blend with black.
  });

  var lineMesh = new THREE.Mesh(lineGeom, lineMaterial);

  // Create THREE Scene and add meshes
  var scene = new THREE.Scene();
  scene.add(mesh);
  scene.add(lineMesh);

  // Workaround: Tag geometry as visible - otherwise it is skipped by computeObjectBounds (see Viewer3DImpl).
  // TODO: My guess is that this is a bug in LMV. Once we know for sure that it doesn't break anything
  //       we should change it in LMV instead and don't need to set this manually anymore.
  geometry.visible = true;
  lineGeom.visible = true;

  // Makes it more debugger-friendly (allow you to recognize this shape within LMV)
  mesh.name = 'FrustumGizmo';

  // Set frustum shape size
  // TODO: Consider smarter way to determine size, e.g. consider model units or model box
  var size = 50;
  scene.scale.set(size, size, size);

  // move tip of the frustum to camera position
  scene.position.copy(pos);

  // orient frustum shape to look towards camera direction
  var origin = new THREE.Vector3(0, 0, 0);
  var up = new THREE.Vector3(0, 0, 1);
  var invDir = new THREE.Vector3(-dir.x, -dir.y, -dir.z); // lookat directions in THREE are defined 'towards' an object
  var rotationMatrix = new THREE.Matrix4().lookAt(origin, invDir, up);
  scene.rotation.setFromRotationMatrix(rotationMatrix);

  // Just disable culling - it's not worth to care about computing BoundingSpheres etc.
  scene.frustumCulled = false;
  mesh.frustumCulled = false;
  lineMesh.frustumCulled = false;

  // Attach function to control overall opacity (fadeValue is in [0,1])
  scene.setFadeValue = function (fadeValue) {
    material.opacity = FrustumOpacity * fadeValue;
    lineMaterial.opacity = LineOpacity * fadeValue;
  };

  return scene;
}

/***/ }),

/***/ "./extensions/AEC/CanvasBookmark/HCluster.js":
/*!***************************************************!*\
  !*** ./extensions/AEC/CanvasBookmark/HCluster.js ***!
  \***************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return HCluster; });
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}var

HCluster = /*#__PURE__*/function () {_createClass(HCluster, null, [{ key: "FlattenCluster", value: function FlattenCluster(
    c) {var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
      if (c.value) {
        values.push(c.value);
      } else
      {
        HCluster.FlattenCluster(c.left, values);
        HCluster.FlattenCluster(c.right, values);
      }

      return values;
    } }, { key: "ComputeMeanValueForFlattenCluster", value: function ComputeMeanValueForFlattenCluster(

    c) {
      var bbox2D = new THREE.Box3();
      var bbox3D = new THREE.Box3();

      c.forEach(function (b) {
        bbox2D.expandByPoint(b.currentPosProjected);
        bbox3D.expandByPoint(b.currentPos3D);
      });

      return {
        center2D: bbox2D.center(),
        center3D: bbox3D.center() };

    } }]);

  function HCluster(clusterfck, distanceFunc) {var threshold = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;_classCallCheck(this, HCluster);
    this._clusterfck = clusterfck;
    this.setDistanceFuncAndThreshold(distanceFunc, threshold);
  }_createClass(HCluster, [{ key: "setDistanceFuncAndThreshold", value: function setDistanceFuncAndThreshold(

    distanceFunc) {var threshold = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
      this._distanceFunc = distanceFunc;
      this._threshold = threshold;
    } }, { key: "setThreshold", value: function setThreshold(

    threshold) {
      this._threshold = threshold;
    } }, { key: "createClusters", value: function createClusters(

    clusterItems) {
      var clusters = this._clusterfck.hcluster(clusterItems, this._distanceFunc, this._clusterfck.AVERAGE_LINKAGE, this._threshold);
      //console.log(clusters);

      return clusters;
    } }]);return HCluster;}();

/***/ }),

/***/ "./extensions/AEC/DropMe/DropMe.css":
/*!******************************************!*\
  !*** ./extensions/AEC/DropMe/DropMe.css ***!
  \******************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {


var content = __webpack_require__(/*! !../../../node_modules/css-loader!./DropMe.css */ "./node_modules/css-loader/index.js!./extensions/AEC/DropMe/DropMe.css");

if(typeof content === 'string') content = [[module.i, content, '']];

var transform;
var insertInto;



var options = {"hmr":true}

options.transform = transform
options.insertInto = undefined;

var update = __webpack_require__(/*! ../../../node_modules/style-loader/lib/addStyles.js */ "./node_modules/style-loader/lib/addStyles.js")(content, options);

if(content.locals) module.exports = content.locals;

if(false) {}

/***/ }),

/***/ "./extensions/AEC/DropMe/DropMe.js":
/*!*****************************************!*\
  !*** ./extensions/AEC/DropMe/DropMe.js ***!
  \*****************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DropMeExtension; });
/* harmony import */ var _DropMeTool_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./DropMeTool.js */ "./extensions/AEC/DropMe/DropMeTool.js");
function _typeof(obj) {if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {_typeof = function _typeof(obj) {return typeof obj;};} else {_typeof = function _typeof(obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};}return _typeof(obj);}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}function _possibleConstructorReturn(self, call) {if (call && (_typeof(call) === "object" || typeof call === "function")) {return call;}return _assertThisInitialized(self);}function _getPrototypeOf(o) {_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {return o.__proto__ || Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function");}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } });if (superClass) _setPrototypeOf(subClass, superClass);}function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);}function _assertThisInitialized(self) {if (self === void 0) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}



var av = Autodesk.Viewing,avu = Autodesk.Viewing.UI;
var namespace = AutodeskNamespace('Autodesk.AEC');
var myExtensionName = 'Autodesk.AEC.DropMeExtension';var

DropMeExtension = /*#__PURE__*/function (_av$Extension) {_inherits(DropMeExtension, _av$Extension);
  function DropMeExtension(viewer) {var _this;var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};_classCallCheck(this, DropMeExtension);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(DropMeExtension).call(this, viewer, options));
    _this.viewer = viewer;
    _this._onModelLoaded = _this._onModelLoaded.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this._deactivateTool = _this._deactivateTool.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.onDropOverride = null;
    _this.supportedViews = options.supportedViews || ['FloorPlan', 'Section'];
    _this.toggleIndex = options.toggleIndex || 0; // at which position at the toolbar to toggle DropMe button
    _this.enableGuidance = options.enableGuidance || false;
    _this.dropMeTool = new _DropMeTool_js__WEBPACK_IMPORTED_MODULE_0__["default"](viewer, function () {var _this2;return (_this2 = _this)._onDrop.apply(_this2, arguments);}, _this._deactivateTool, function (v) {return DropMeExtension.isSuppotedViewport(v, _this.supportedViews);});return _this;
  }_createClass(DropMeExtension, [{ key: "load", value: function load()

    {
      this.viewer.addEventListener(av.MODEL_ADDED_EVENT, this._onModelLoaded);
      if (this.viewer.model) {
        this._initUI(this.viewer.model);
      }
      return true;
    } }, { key: "unload", value: function unload()

    {
      this.viewer.removeEventListener(av.MODEL_ADDED_EVENT, this._onModelLoaded);
      this._deactivateTool();
      this._destroyUI();
      return true;
    } }, { key: "setOnDrop", value: function setOnDrop(

    cb) {
      this.onDropOverride = cb;
    } }, { key: "_destroyUI", value: function _destroyUI()

    {
      this._showDrop(false);
      var toolbar = this.viewer.getToolbar(false);
      var modelTools = toolbar.getControl(av.TOOLBAR.NAVTOOLSID);
      modelTools.removeControl(this.dropMeButton);
      this.dropMeButton = null;
    } }, { key: "_onDrop", value: function _onDrop(

    pos, dir, mode) {
      // after drop action had been triggered, we need to deactivate tool as we are transitioning into another view.
      this.viewer.toolController.setIsLocked(false);
      this._deactivateTool();

      console.log("DropMe: 3D camera position is ".concat(JSON.stringify(pos)));
      console.log("DropMe: 3D camera direction is ".concat(JSON.stringify(dir)));

      if (this.onDropOverride) {
        this.onDropOverride(pos, dir, mode);
      } else if (this.options.onDrop) {
        this.options.onDrop(pos, dir, mode);
      } else {
        console.warn('DropMe: No onDrop callback specified ');
      }
    } }, { key: "_onModelLoaded", value: function _onModelLoaded(

    event) {
      if (!this.uiInitialized) {
        this._initUI(event.model);
      } else {
        this._updateUI(event.model);
      }
    } }, { key: "_deactivateTool", value: function _deactivateTool()

    {
      this._showGuidenaceUI(false);
      this.dropMeButton.setState(avu.Button.State.INACTIVE);
      this.viewer.toolController.deactivateTool('drop-me');
    } }, { key: "_isSupportedModel", value: function _isSupportedModel(

    model) {var _this3 = this;
      var is2dAEC = model && model.isAEC && model.isAEC() && model.is2d();
      if (!is2dAEC) {
        return false;
      }

      if (!model.getDocumentNode()) {
        return false;
      }

      var viewports = this.dropMeTool.findViewports(model);

      // Here we are just checking whether it makes sense to start working with this model by checking that
      // at least one viewport is fine
      return viewports.length && viewports.find(function (v) {return DropMeExtension.isSuppotedViewport(v, _this3.supportedViews);});
    } }, { key: "_updateUI", value: function _updateUI(










    model) {
      var toolbar = this.viewer.getToolbar(false);
      var modelTools = toolbar.getControl(av.TOOLBAR.NAVTOOLSID);
      modelTools.addControl(this.dropMeButton, { index: this.toggleIndex });
      this._showDrop(this._isSupportedModel(model));
    } }, { key: "_initUI", value: function _initUI(

    model) {var _this4 = this;
      this.dropMeButton = new avu.Button('drop-me-icon');
      this.dropMeButton.icon.innerHTML = createDropMeIcon();

      this._updateUI(model);
      this.dropMeButton.onClick = function () {
        if (_this4.dropMeTool.active) {
          _this4._deactivateTool();
        } else {
          _this4.dropMeButton.setState(avu.Button.State.ACTIVE);
          // TODO: when we activate tool we might want to forbid interaction with other tools
          _this4.viewer.toolController.activateTool('drop-me');
          _this4._showGuidenaceUI();
        }
      };
      this.uiInitialized = true;
    } }, { key: "_showGuidenaceUI", value: function _showGuidenaceUI()

    {var show = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
      if (!this.enableGuidance)
      return;

      if (show) {
        this.guidenaceUI = document.createElement('div');
        this.guidenaceUI.className = 'dropme-guidenace-ui';
        this.guidenaceUI.innerHTML = Autodesk.Viewing.i18n.translate('Click on a location to ground yourself, then select a camera direction');
        this.viewer.container.appendChild(this.guidenaceUI);
      } else {
        if (this.viewer.container.contains(this.guidenaceUI)) {
          this.viewer.container.removeChild(this.guidenaceUI);
        }
      }
    } }, { key: "_showDrop", value: function _showDrop(

    value) {
      if (!this.dropMeButton) {
        return;
      }

      var toolbar = this.viewer.getToolbar(false);
      var modelTools = toolbar.getControl(av.TOOLBAR.NAVTOOLSID);

      if (modelTools && !this.container) {
        this.dropMeButton.setState(value ? avu.Button.State.INACTIVE : avu.Button.State.DISABLED);
      }
      var supportedTooltip = Autodesk.Viewing.i18n.translate('Click a 2D location to view that space in 3D');
      var unsupportedTooltip = Autodesk.Viewing.i18n.translate('Current view is not supported by Place Me');

      this.dropMeButton.setToolTip(value ? supportedTooltip : unsupportedTooltip);
    } }], [{ key: "isSuppotedViewport", value: function isSuppotedViewport(vp, supportedViews) {return vp.sectionBox && vp.geometryViewportRegion && vp.isCropBoxActive && !vp.hasBreaks && !vp.extensions.hasRegions && supportedViews.indexOf(vp.viewType) >= 0;} }]);return DropMeExtension;}(av.Extension);


var createDropMeIcon = function createDropMeIcon() {
  return [
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">',
  '<g stroke="currentColor" fill="currentColor">',
  '<path d="M67,0c2.4.5,4.8.9,7.1,1.6C87.5,5.3,96.6,16.6,98,31a37.2,37.2,0,0,1-2.1,16.2c-4.7,13-23.6,48.1-31.6,58.2-.3-.2-.6-.3-.8-.5-11.1-17.6-21.9-35.4-30-54.7-4.6-10.9-4.6-21.7.6-32.3S47.5,2.6,58.3.7l3-.7ZM64,47A11.8,11.8,0,1,0,52.3,34.9,12,12,0,0,0,64,47Z"/>',
  '<path d="M12.8,103.4c1.4-8,6.9-12.3,14-14.6s12-2.9,18.1-4.2c1.1-.2,2.4.5,3.4,1.5-4.5,1.1-9.1,1.8-13.5,3.3a35,35,0,0,0-9.6,5c-4,3-4.3,7.5-.7,10.9a28.7,28.7,0,0,0,9.6,6.2,87.3,87.3,0,0,0,59.9.1,28.2,28.2,0,0,0,8.7-5.2c4.9-4.1,4.8-9.7-.8-12.8S90.7,89.3,85,87.3c-1.6-.6-3.4-.6-5.3-1.7,1.1-.4,2.2-1.2,3.2-1.1,7.8.9,15.5,2.2,22.6,6,12,6.4,13,17.9,2.1,26.1-8.1,6.1-17.6,8.5-27.4,10L69.1,128H59.2l-5.2-.7c-9.1-.8-18-2.6-26.4-6.5s-13.4-8.1-14.9-16.8Z"/>',
  '</g>',
  '</svg>'].
  join('');
};

namespace.DropMeExtension = DropMeExtension;

Autodesk.Viewing.theExtensionManager.registerExtension(myExtensionName, DropMeExtension);

/***/ }),

/***/ "./extensions/AEC/DropMe/DropMeTool.js":
/*!*********************************************!*\
  !*** ./extensions/AEC/DropMe/DropMeTool.js ***!
  \*********************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DropMeTool; });
/* harmony import */ var _ViewPortOverlay_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ViewPortOverlay.js */ "./extensions/AEC/DropMe/ViewPortOverlay.js");
function _typeof(obj) {if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {_typeof = function _typeof(obj) {return typeof obj;};} else {_typeof = function _typeof(obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};}return _typeof(obj);}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}function _possibleConstructorReturn(self, call) {if (call && (_typeof(call) === "object" || typeof call === "function")) {return call;}return _assertThisInitialized(self);}function _getPrototypeOf(o) {_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {return o.__proto__ || Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function");}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } });if (superClass) _setPrototypeOf(subClass, superClass);}function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);}function _assertThisInitialized(self) {if (self === void 0) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}



var av = Autodesk.Viewing,avp = av.Private;

var DROPME_MODE = { auto: 'Auto', manual: 'Manual' };var

DropMeTool = /*#__PURE__*/function (_av$ToolInterface) {_inherits(DropMeTool, _av$ToolInterface);
  function DropMeTool(viewer, onDrop, triggerDeactivate, isSupportedViewport) {var _this;_classCallCheck(this, DropMeTool);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(DropMeTool).call(this));

    _this.names = ['drop-me'];
    _this.viewer = viewer;
    _this.viewer.toolController.registerTool(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.onDrop = onDrop;
    _this.triggerDeactivate = triggerDeactivate;
    _this.isSupportedViewport = isSupportedViewport;
    _this.active = false;
    _this._movedSinceFirstClick = false;
    _this.init();

    _this.cameraSelectionState = {
      pending: false,
      pos: null,
      target: null,
      inViewport: false,
      initialVp: null };


    _this.teleportationInProgress = 0;

    // 'False' indicates if the user has clicked a first time alredy to choose position, so that the
    // next click will determine view-direction and instantly invoke the transition.
    _this.isFirstClick = true;

    _this.viewPortOverlay = new _ViewPortOverlay_js__WEBPACK_IMPORTED_MODULE_0__["default"](_this.viewer);
    _this.escapeHotkeyId = 'Autodesk.AEC.DropMeToolEsc';return _this;
  }_createClass(DropMeTool, [{ key: "init", value: function init()

    {var _this2 = this;
      this.activate = function () {
        var hotkeys = [{
          keycodes: [
          Autodesk.Viewing.KeyCode.ESCAPE],

          onRelease: function onRelease() {return _this2.triggerDeactivate && _this2.triggerDeactivate();} }];

        _this2.viewer.getHotkeyManager().pushHotkeys(_this2.escapeHotkeyId, hotkeys);
        _this2.viewer.addEventListener(av.MODEL_ADDED_EVENT, _this2.triggerDeactivate);
        _this2.viewer.impl.pauseHighlight(true);
        _this2.active = true;
      };

      this.deactivate = function () {
        _this2.viewer.getHotkeyManager().popHotkeys(_this2.escapeHotkeyId);
        _this2._cancelTeleportation();
        _this2._destroyCameraSelectorUi();
        _this2.viewer.removeEventListener(av.MODEL_ADDED_EVENT, _this2.triggerDeactivate);
        _this2.viewer.impl.pauseHighlight(false);
        _this2.active = false;
        _this2._movedSinceFirstClick = false;
      };

      this.handleSingleClick = function (e) {
        if (_this2.isFirstClick) {
          var tmpres = _this2._get3DCameraPositionAndVp(e.canvasX, e.canvasY);
          if (tmpres && tmpres.pos) {
            _this2.cameraSelectionState.pos = { x: e.canvasX, y: e.canvasY };
            _this2.cameraSelectionState.pending = true;
            _this2.cameraSelectionState.initialVp = tmpres.vp;

            _this2._createCameraSelectorUi(_this2.cameraSelectionState.pos);

            requestAnimationFrame(function () {
              // We should only trigger animation if mouse has not been moved since the first click.
              if (!_this2._movedSinceFirstClick)
              _this2.cameraSelectorPosition.classList.add('camera-selector-position--teleporting');
            });

            if (tmpres.vp.viewType !== 'Section') {
              // while teleportation is pending this.handleMouseMove will move camera frustum
              _this2._scheduleTeleportation();

              // needed only for scheduled teleportation
              _this2.isFirstClick = false;
              _this2.cursor = 'none';
              _this2.getCursor();
            } else
            {
              _this2._runTeleportation(DROPME_MODE.auto);
            }
          }
        } else
        {
          //console.log(`camera target at ${e.canvasX}, ${e.canvasY}`);
          _this2.cameraSelectionState.target = { x: e.canvasX, y: e.canvasY };
          _this2._runTeleportation(DROPME_MODE.manual);
          _this2.isFirstClick = true;
          _this2._movedSinceFirstClick = false;
          _this2._recoverCursor();
        }

        // As expectation of single click is a teleportation to another view, we simply consume event and do not propogate it further
        return true;
      };

      this.handleMouseMove = function (e) {
        if (!_this2.isFirstClick && !_this2._movedSinceFirstClick)
        _this2._movedSinceFirstClick = true;

        if (_this2.cursor)
        _this2._recoverCursor();

        var tmpres = _this2._get3DCameraPositionAndVp(e.canvasX, e.canvasY);

        if (_this2.cameraSelectionState.initialVp && !_this2.isFirstClick) {
          _this2._addVpOverlay(_this2.cameraSelectionState.initialVp);
        } else
        if (tmpres && tmpres.pos) {
          _this2._addVpOverlay(tmpres.vp);
        } else
        {
          _this2.viewPortOverlay.removeOverlay();
        }

        _this2.cameraSelectionState.inViewport = _this2.isFirstClick && tmpres && tmpres.pos || !_this2.isFirstClick;
        _this2.getCursor();

        if (!_this2.cameraSelectionState.pending) {
          return;
        }

        if (_this2.teleportationInProgress) {
          // cancel position animation
          _this2.cameraSelectorPosition.classList.remove('camera-selector-position--teleporting');
          clearTimeout(_this2.teleportationInProgress);
          _this2.teleportationInProgress = 0;
        }

        var dx = e.canvasX - _this2.cameraSelectionState.pos.x;
        var dy = e.canvasY - _this2.cameraSelectionState.pos.y;
        var angle = Math.atan2(dy, dx) * 180 / Math.PI;

        // atan measures the angle to the x-axis, but the frustum gizmo is originally aligned with y.
        angle += 90;

        _this2.cameraSelector.style.transform = "rotate(".concat(angle, "deg)");

        //console.log(angle);
        return true;
      };

      this.handleResize = function () {
        // As teleportation is going to be rather short interaction with a short-living UI, we just do not handle screen resize at all for now, but deactivate tool instead.
        _this2.triggerDeactivate && _this2.triggerDeactivate();
      };
    } }, { key: "_recoverCursor", value: function _recoverCursor()

    {
      this.cursor = null;
      this.getCursor();
    } }, { key: "getCursor", value: function getCursor()

    {
      if (this.cursor)
      return this.cursor;
      return this.cameraSelectionState.inViewport ? 'cell' : 'default';
    } }, { key: "_addVpOverlay", value: function _addVpOverlay(

    vp) {
      this.viewPortOverlay.removeOverlay();
      var vpRect = this._viewPortToRect(vp);
      var min = vpRect.min;
      var max = vpRect.max;
      this.viewPortOverlay.addOverlay(min.x, min.y, max.x, max.y);
    }

    // mode is only required for analytics purposes
  }, { key: "_runTeleportation", value: function _runTeleportation(mode) {
      this._mapToCameraPositionIn3D(mode);
      this._cancelTeleportation();
    } }, { key: "_scheduleTeleportation", value: function _scheduleTeleportation()

    {var _this3 = this;
      this.teleportationInProgress = setTimeout(function () {
        _this3._runTeleportation(DROPME_MODE.auto);
      }, 3000); // this timeout is alligned with coresponding rule of camera-selector-position css class
    } }, { key: "_cancelTeleportation", value: function _cancelTeleportation()

    {
      if (this.teleportationInProgress) {
        clearTimeout(this.teleportationInProgress);
        this.teleportationInProgress = 0;
      }
    } }, { key: "_createCameraSelectorUi", value: function _createCameraSelectorUi(

    pos) {
      //console.log(`camera position at ${pos.x}, ${pos.y}`);
      this.cameraSelectorBackground = document.createElement('div');
      this.cameraSelectorBackground.className = 'camera-selector-background';
      this.viewer.container.appendChild(this.cameraSelectorBackground);
      this.cameraSelectorBackground.style.top = "".concat(pos.y, "px");
      this.cameraSelectorBackground.style.left = "".concat(pos.x, "px");

      this.cameraSelectorPosition = document.createElement('div');
      this.cameraSelectorPosition.className = 'camera-selector-position';
      this.viewer.container.appendChild(this.cameraSelectorPosition);
      this.cameraSelectorPosition.style.top = "".concat(pos.y - 10, "px");
      this.cameraSelectorPosition.style.left = "".concat(pos.x - 10, "px");

      this.cameraSelector = document.createElement('div');
      this.cameraSelector.className = 'camera-selector';
      this.viewer.container.appendChild(this.cameraSelector);
      this.cameraSelector.style.top = "".concat(pos.y - 100, "px");
      this.cameraSelector.style.left = "".concat(pos.x - 50, "px");
    } }, { key: "_destroyCameraSelectorUi", value: function _destroyCameraSelectorUi()

    {
      if (this.viewer.container.contains(this.cameraSelector)) {
        this.viewer.container.removeChild(this.cameraSelector);
      }

      if (this.viewer.container.contains(this.cameraSelectorBackground)) {
        this.viewer.container.removeChild(this.cameraSelectorBackground);
      }

      if (this.viewer.container.contains(this.cameraSelectorPosition)) {
        this.viewer.container.removeChild(this.cameraSelectorPosition);
      }

      this.cameraSelectionState = {
        pending: false,
        pos: null,
        target: null,
        inViewport: false,
        initialVp: null };


      this.isFirstClick = true;

      this.viewPortOverlay.removeOverlay();
    } }, { key: "_getAECData", value: function _getAECData(

    model) {
      var node = model.myData.loadOptions.bubbleNode;
      var root = node.getRootNode();
      return root.getAecModelData();
    }

    // Finds all viewports on a current sheet
  }, { key: "findViewports", value: function findViewports(model) {
      var aec = this._getAECData(model);
      if (!aec || !aec.viewports) {
        return [];
      }
      var node = model.myData.loadOptions.bubbleNode;
      var result = aec.viewports.
      filter(this.isSupportedViewport).
      filter(function (vp) {return vp.sheetGuid === node.data.guid;});
      return result;
    }

    // Given F2D world coords (Vec3), this function returns the viewport that was hit.
  }, { key: "_findViewport", value: function _findViewport(f2dWorldPos) {var _this4 = this;
      var p2d = new THREE.Vector2(f2dWorldPos.x, f2dWorldPos.y);

      var viewports = this.findViewports(this.viewer.model).map(function (vp) {var
        viewType = vp.viewType,geometryViewportRegion = vp.geometryViewportRegion,sectionBox = vp.sectionBox,extensions = vp.extensions,viewportRotation = vp.viewportRotation;
        var rect = _this4._viewPortToRect(vp);

        var _vp = {
          viewType: viewType,
          rect: rect,
          geometryViewportRegion: geometryViewportRegion, // the same as viewportPosition, but excluding annotations
          viewportRotation: viewportRotation,
          sectionBox: sectionBox,
          extensions: extensions,
          srcData: vp // for debugging. Otherwise it's annoying that you cannot see all relevant aecModelData values anywhere
        };

        return _vp;
      });

      var sortedByDistance = viewports.
      filter(function (vp) {
        return vp.rect.containsPoint(p2d);
      }).
      sort(function (vpA, vpB) {
        var distA = Math.min(
        Math.min(p2d.x - vpA.rect.min.x, vpA.rect.max.x - p2d.x),
        Math.min(p2d.y - vpA.rect.min.y, vpA.rect.max.y - p2d.y));


        var distB = Math.min(
        Math.min(p2d.x - vpB.rect.min.x, vpB.rect.max.x - p2d.x),
        Math.min(p2d.y - vpB.rect.min.y, vpB.rect.max.y - p2d.y));


        return distB - distA;
      });

      return sortedByDistance.length > 0 ? sortedByDistance[0] : null;
    } }, { key: "_viewPortToRect", value: function _viewPortToRect(

    viewport) {
      // viewport position in foot as array (6 floats)
      var pos = viewport.geometryViewportRegion;
      var res = new THREE.Box2();
      var sc = this.viewer.model.getUnitScale();
      // convert bbox to model units or to inches if model units are unknown.
      var unitScale = sc !== 1 ? 0.3048 / sc : 12;
      res.min.x = pos[0] * unitScale;
      res.min.y = pos[1] * unitScale;
      res.max.x = pos[3] * unitScale;
      res.max.y = pos[4] * unitScale;
      return res;
    }

    // Handle available view rotation modes in Revit
    // If a view was rotated in Revit, this swapped/inverted some viewport axes. We must revert this modification when transforming back to world coords.
    //
    //  @param {THREE.Vector2/3} vpCoords     - Normalized viewport coords.
    //  @param {number}          viewportType - as read from AECModelData. Enum value in {0,1,2}. see Revit API doc:
    //                                          http://www.revitapidocs.com/2018/abd81744-b44a-e578-cb62-3cc40a334acc.htm
    //  @returns {THREE.Vector2/3} Copy of vpCoords with swapped/inverted axes according to viewport rotation
  }, { key: "_applyInverseViewportRotation", value: function _applyInverseViewportRotation(vpCoords, viewRotationType) {

      var result = vpCoords.clone(); // Vector2 or Vector3, depending on input.
      switch (viewRotationType) {
        // No rotation => done
        case 0:break;

        // Revit view was rotated by 90 degrees clockwise => Rotate by 90 degrees ccw
        case 1:{
            // Note that a rotation would actually mean result.x = -y. But, we just revert the effect the rotation effect on the
            // viewport axes here. I.e., input and output are in [0,1]. For this, swapping an axis means taking 1.0-value, not just the negative.
            result.x = 1.0 - vpCoords.y;
            result.y = vpCoords.x;
            break;
          }

        // Revit view was rotated 90 degrees counterclockwise => Rotate by 90 degrees cw
        case 2:{
            result.x = vpCoords.y;
            result.y = 1.0 - vpCoords.x;
            break;
          }

        default:console.warn('Unexpected enum value for view rotation: ', viewRotationType);}

      return result;
    }

    // Returns Vector2 in [0,1]^2 indicating the relative position inside the given viewport
  }, { key: "_getNormalizedViewportCoords", value: function _getNormalizedViewportCoords(viewport, worldPos) {
      var rect = viewport.rect;
      var xRel = (worldPos.x - rect.min.x) / (rect.max.x - rect.min.x);
      var yRel = (worldPos.y - rect.min.y) / (rect.max.y - rect.min.y);
      return new THREE.Vector2(xRel, yRel);
    } }, { key: "_mapToCameraPositionIn3DForFloorplan", value: function _mapToCameraPositionIn3DForFloorplan(

    pos, mode) {
      var posGeorefed = this._applyGeoRefTransform(pos);

      var dir = new THREE.Vector3(0.0, 1.0, 0.0);

      // in the case of not specified target, use north direction
      if (this.cameraSelectionState.target) {
        var x = this.cameraSelectionState.target.x;
        var y = this.cameraSelectionState.target.y;

        var resTarget = this._get3DCameraPositionAndVp(x, y, true);
        if (resTarget && resTarget.pos) {
          var targetGeorefed = this._applyGeoRefTransform(resTarget.pos);

          dir.x = targetGeorefed.x - posGeorefed.x;
          dir.y = targetGeorefed.y - posGeorefed.y;
          // dir.z will remain zero since we are residing in a plane
        }

        var length = Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
        dir.x /= length;
        dir.y /= length;
      }

      // mimic natural looking direction which is not really parallel to the ground
      var rotAxis = new THREE.Vector3(-dir.y, dir.x, 0.0);
      dir.applyAxisAngle(rotAxis, Math.PI / 18.0); // 10 degrees

      this.onDrop(posGeorefed, dir, mode);
    } }, { key: "_mapToCameraPositionIn3DForSection", value: function _mapToCameraPositionIn3DForSection(

    pos, mode) {
      var posGeorefed = this._applyGeoRefTransform(pos);

      // by default we are looking into the north direction, in this case "into the screen"
      var dir = new THREE.Vector3(0.0, 1.0, 0.0);

      // mimic natural looking direction which is not really parallel to the ground
      var rotAxis = new THREE.Vector3(-dir.y, dir.x, 0.0);
      dir.applyAxisAngle(rotAxis, Math.PI / 18.0); // 10 degrees

      this.onDrop(posGeorefed, dir, mode);
    }

    // if we will come up with a good visualization widget for dir selection for "Section" views
    // the two methods "_mapToCameraPositionIn3DForFloorplan()" and "_mapToCameraPositionIn3DForSection()"
    // could be unified. we will still have two cases in "if (resTarget && resTarget.pos) {...}" code path
    //   1. FloorPlan: x,y - change, z - constant
    //   2. Section:   x - changes, y,z - constant
  }, { key: "_mapToCameraPositionIn3D", value: function _mapToCameraPositionIn3D() {var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DROPME_MODE.manual;
      var x = this.cameraSelectionState.pos.x;
      var y = this.cameraSelectionState.pos.y;
      var resPos = this._get3DCameraPositionAndVp(x, y);

      if (resPos && resPos.pos && resPos.vp) {
        if (resPos.vp.viewType === 'FloorPlan' || resPos.vp.viewType === 'EngineeringPlan' || resPos.vp.viewType === 'CeilingPlan') {
          this._mapToCameraPositionIn3DForFloorplan(resPos.pos, mode);
        } else
        if (resPos.vp.viewType === 'Section') {
          this._mapToCameraPositionIn3DForSection(resPos.pos, DROPME_MODE.auto);
        }
      }
    } }, { key: "_findLevelForViewport", value: function _findLevelForViewport(

    viewport) {
      if (!viewport.extensions.viewRange) {
        return undefined;
      }

      var guid = viewport.extensions.viewRange.cutPlane.levelGuid;
      var aec = this._getAECData(this.viewer.model);
      return aec.levels.find(function (level) {return level.guid === guid;});
    }

    // Convert normalized viewport coords in [0,1] of a view in a 2D sheet to 3D world coords
  }, { key: "_viewportTo3D", value: function _viewportTo3D(vp, normVpCoord) {
      var sb = vp.sectionBox;

      // calculate (x,y) values on section box front plane
      var x = avp.lerp(sb.min.x, sb.max.x, normVpCoord.x);
      var y = avp.lerp(sb.min.y, sb.max.y, normVpCoord.y);
      var z = 0.0; // corresponds to sb.max.z

      // assumption for "Section" views: Zmax = 0 (before applying transform) will always be the plane closest to the camera which recorded the view
      // transform should always rotate it to a vertical plane
      var pWorld = new THREE.Vector3(x, y, z);

      var matrix = av.BubbleNode.readMatrixFromArray12(sb.transform);
      pWorld.applyMatrix4(matrix);
      //console.log(pWorld.z);

      return pWorld;
    } }, { key: "_get3DCameraPositionAndVp", value: function _get3DCameraPositionAndVp(

    x, y) {var useInitialVp = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
      var vpVec = this.viewer.impl.clientToViewport(x, y);
      var point = this.viewer.impl.intersectGroundViewport(vpVec);

      // if no viewport can be found for the current mouse position on a second click, try to use initial viewport
      var hitViewport = this._findViewport(point) || useInitialVp && this.cameraSelectionState.initialVp;
      if (!hitViewport) {
        // Clicked outside of the viewport
        // DropMe tool remains active and allows user to pick another point
        return null;
      }

      var normVpCoord = this._getNormalizedViewportCoords(hitViewport, point);

      // consider potential viewport rotation
      normVpCoord = this._applyInverseViewportRotation(normVpCoord, hitViewport.viewportRotation);

      var pWorld = this._viewportTo3D(hitViewport, normVpCoord);

      // Derive z from level metadata
      if (hitViewport.viewType === 'FloorPlan') {
        var level = this._findLevelForViewport(hitViewport);
        if (level) {
          var avatarHeight = 5.74147; // 1.75m
          pWorld.z = level.elevation + avatarHeight;
          //console.log(pWorld.z);
        }
      }

      return {
        pos: pWorld,
        vp: hitViewport };

    } }, { key: "_applyGeoRefTransform", value: function _applyGeoRefTransform(

    pos) {
      var vec = pos.clone();

      // This extension requires AEC model data, so there should always be a refPoint tranform
      var root = this.viewer.model.getDocumentNode().getRootNode();
      var matrix = root.extractRefPointTransform();
      vec.applyMatrix4(matrix);

      return vec;
    } }]);return DropMeTool;}(av.ToolInterface);

/***/ }),

/***/ "./extensions/AEC/DropMe/ViewPortOverlay.js":
/*!**************************************************!*\
  !*** ./extensions/AEC/DropMe/ViewPortOverlay.js ***!
  \**************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ViewPortOverlay; });
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}

var av = Autodesk.Viewing,avp = av.Private;var

ViewPortOverlay = /*#__PURE__*/function () {
  function ViewPortOverlay(viewer) {_classCallCheck(this, ViewPortOverlay);
    this.viewer = viewer;
    this.overlayName = 'DropMeViewPortOverlay';
  }_createClass(ViewPortOverlay, [{ key: "addOverlay", value: function addOverlay(

    xMin, yMin, xMax, yMax) {
      this.viewer.impl.createOverlayScene(this.overlayName);

      var mesh = this._createMesh(xMin, yMin, xMax, yMax);
      this.viewer.impl.addOverlay(this.overlayName, mesh);
    } }, { key: "removeOverlay", value: function removeOverlay()

    {
      this.viewer.impl.removeOverlayScene(this.overlayName);
    } }, { key: "_createMesh", value: function _createMesh(

    xMin, yMin, xMax, yMax) {
      var vpId = 0;
      var dbId = -1;
      var layer = 0;
      var borderColor = 0x99d79606;
      var lineWidth = 0.1;
      var totalDist = 0;

      var vbb = new avp.VertexBufferBuilder(false, undefined, 4);

      // add border
      vbb.addSegment(xMin, yMin, xMax, yMin, totalDist, lineWidth, borderColor, dbId, layer, vpId);
      vbb.addSegment(xMax, yMin, xMax, yMax, totalDist, lineWidth, borderColor, dbId, layer, vpId);
      vbb.addSegment(xMax, yMax, xMin, yMax, totalDist, lineWidth, borderColor, dbId, layer, vpId);
      vbb.addSegment(xMin, yMax, xMin, yMin, totalDist, lineWidth, borderColor, dbId, layer, vpId);

      var meshData = vbb.toMesh();
      var mdata = {
        mesh: meshData,
        is2d: true,
        packId: '0',
        meshIndex: 1 };


      avp.BufferGeometryUtils.meshToGeometry(mdata);
      var geom = mdata.geometry;

      var materialParams = {
        skipEllipticals: true,
        skipCircles: true,
        skipTriangleGeoms: true,
        useInstancing: false };


      var matman = this.viewer.impl.matman();
      var matName = matman.create2DMaterial(this.viewer.impl.model, materialParams);
      var material = matman.findMaterial(this.viewer.impl.model, matName);

      var mesh = new THREE.Mesh(geom, material);
      return mesh;
    } }]);return ViewPortOverlay;}();

/***/ }),

/***/ "./extensions/AEC/LibraryExports.js":
/*!******************************************!*\
  !*** ./extensions/AEC/LibraryExports.js ***!
  \******************************************/
/*! exports provided: FloorSelector, ListPanel, ListPanelEvents, LevelsExtension, HyperlinkTracker, HyperlinkExtension, DropMeExtension, CanvasBookmarkExtension, MinimapTool, Minimap3DExtension */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _ui_ListPanel_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ui/ListPanel.css */ "./extensions/AEC/ui/ListPanel.css");
/* harmony import */ var _ui_ListPanel_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_ui_ListPanel_css__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _DropMe_DropMe_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./DropMe/DropMe.css */ "./extensions/AEC/DropMe/DropMe.css");
/* harmony import */ var _DropMe_DropMe_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_DropMe_DropMe_css__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _CanvasBookmark_CanvasBookmark_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./CanvasBookmark/CanvasBookmark.css */ "./extensions/AEC/CanvasBookmark/CanvasBookmark.css");
/* harmony import */ var _CanvasBookmark_CanvasBookmark_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_CanvasBookmark_CanvasBookmark_css__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _levels_FloorSelector_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./levels/FloorSelector.js */ "./extensions/AEC/levels/FloorSelector.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FloorSelector", function() { return _levels_FloorSelector_js__WEBPACK_IMPORTED_MODULE_3__["default"]; });

/* harmony import */ var _levels_LevelsExtension_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./levels/LevelsExtension.js */ "./extensions/AEC/levels/LevelsExtension.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "LevelsExtension", function() { return _levels_LevelsExtension_js__WEBPACK_IMPORTED_MODULE_4__["default"]; });

/* harmony import */ var _hyperlinks_HyperlinkTracker_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./hyperlinks/HyperlinkTracker.js */ "./extensions/AEC/hyperlinks/HyperlinkTracker.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "HyperlinkTracker", function() { return _hyperlinks_HyperlinkTracker_js__WEBPACK_IMPORTED_MODULE_5__["default"]; });

/* harmony import */ var _hyperlinks_HyperlinkExtension_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./hyperlinks/HyperlinkExtension.js */ "./extensions/AEC/hyperlinks/HyperlinkExtension.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "HyperlinkExtension", function() { return _hyperlinks_HyperlinkExtension_js__WEBPACK_IMPORTED_MODULE_6__["default"]; });

/* harmony import */ var _ui_ListPanel__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./ui/ListPanel */ "./extensions/AEC/ui/ListPanel.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ListPanel", function() { return _ui_ListPanel__WEBPACK_IMPORTED_MODULE_7__["ListPanel"]; });

/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ListPanelEvents", function() { return _ui_ListPanel__WEBPACK_IMPORTED_MODULE_7__["ListPanelEvents"]; });

/* harmony import */ var _DropMe_DropMe_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./DropMe/DropMe.js */ "./extensions/AEC/DropMe/DropMe.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DropMeExtension", function() { return _DropMe_DropMe_js__WEBPACK_IMPORTED_MODULE_8__["default"]; });

/* harmony import */ var _CanvasBookmark_CanvasBookmark_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./CanvasBookmark/CanvasBookmark.js */ "./extensions/AEC/CanvasBookmark/CanvasBookmark.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "CanvasBookmarkExtension", function() { return _CanvasBookmark_CanvasBookmark_js__WEBPACK_IMPORTED_MODULE_9__["default"]; });

/* harmony import */ var _Minimap3D_Minimap3D_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./Minimap3D/Minimap3D.js */ "./extensions/AEC/Minimap3D/Minimap3D.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Minimap3DExtension", function() { return _Minimap3D_Minimap3D_js__WEBPACK_IMPORTED_MODULE_10__["default"]; });

/* harmony import */ var _Minimap3D_MinimapTool_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./Minimap3D/MinimapTool.js */ "./extensions/AEC/Minimap3D/MinimapTool.js");
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MinimapTool", function() { return _Minimap3D_MinimapTool_js__WEBPACK_IMPORTED_MODULE_11__["default"]; });



// Each one of these CSS imports gets injected into the HTML's headers inside its own <style>.
















/***/ }),

/***/ "./extensions/AEC/Minimap3D/FuzzyBox.js":
/*!**********************************************!*\
  !*** ./extensions/AEC/Minimap3D/FuzzyBox.js ***!
  \**********************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return fuzzyBox; });

// Sum of all fragment bbox centers, each weighted by bbox size
function centerOfMass(model) {

  var frags = model.getFragmentList();

  var box = new THREE.Box3();
  var center = new THREE.Vector3();
  var size = new THREE.Vector3();
  var total = new THREE.Vector3();
  var mass = 0;

  function processOneFragment(f) {

    // get bbox center
    frags.getWorldBounds(f, box);
    box.center(center);

    // sum centers weighted by bbox size
    var weight = box.size(size).length();
    total.add(center.multiplyScalar(weight));

    mass += weight;
  }

  for (var i = 0; i < frags.getCount(); i++) {
    processOneFragment(i);
  }

  total.multiplyScalar(1 / mass);
  return total;
}

// Computes bbox of all fragments, but excluding outliers.
function fuzzyBox(model, center, quantil) {

  center = center || centerOfMass(model);
  quantil = quantil || 0.75;

  var frags = model.getFragmentList();
  var fragBox = new THREE.Box3();

  // Compute distances of each frag bbox from center
  var fragInfos = [];
  for (var i = 0; i < frags.getCount(); i++) {

    // get fragBox->center distance
    frags.getWorldBounds(i, fragBox);
    var dist = fragBox.distanceToPoint(center);

    // If fragBox contains the center, use fragBox center.
    if (dist == 0) {
      dist = center.distanceTo(fragBox.center());
    }

    fragInfos.push({
      fragId: i,
      distance: dist });

  }

  // sort by increasing order    
  fragInfos.sort(function (a, b) {
    return a.distance - b.distance;
  });

  // union of all fragBoxes, excluding the ones with largest distance to center
  var box = new THREE.Box3();
  for (var i = 0; i < fragInfos.length * quantil; i++) {
    var fi = fragInfos[i];
    frags.getWorldBounds(fi.fragId, fragBox);
    box.union(fragBox);
  }
  return box;
}

/***/ }),

/***/ "./extensions/AEC/Minimap3D/Minimap3D.css":
/*!************************************************!*\
  !*** ./extensions/AEC/Minimap3D/Minimap3D.css ***!
  \************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {


var content = __webpack_require__(/*! !../../../node_modules/css-loader!./Minimap3D.css */ "./node_modules/css-loader/index.js!./extensions/AEC/Minimap3D/Minimap3D.css");

if(typeof content === 'string') content = [[module.i, content, '']];

var transform;
var insertInto;



var options = {"hmr":true}

options.transform = transform
options.insertInto = undefined;

var update = __webpack_require__(/*! ../../../node_modules/style-loader/lib/addStyles.js */ "./node_modules/style-loader/lib/addStyles.js")(content, options);

if(content.locals) module.exports = content.locals;

if(false) {}

/***/ }),

/***/ "./extensions/AEC/Minimap3D/Minimap3D.js":
/*!***********************************************!*\
  !*** ./extensions/AEC/Minimap3D/Minimap3D.js ***!
  \***********************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Minimap3DExtension; });
/* harmony import */ var _MinimapTool_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./MinimapTool.js */ "./extensions/AEC/Minimap3D/MinimapTool.js");
/* harmony import */ var _FuzzyBox_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./FuzzyBox.js */ "./extensions/AEC/Minimap3D/FuzzyBox.js");
/* harmony import */ var _Minimap3D_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Minimap3D.css */ "./extensions/AEC/Minimap3D/Minimap3D.css");
/* harmony import */ var _Minimap3D_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_Minimap3D_css__WEBPACK_IMPORTED_MODULE_2__);
function _typeof(obj) {if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {_typeof = function _typeof(obj) {return typeof obj;};} else {_typeof = function _typeof(obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};}return _typeof(obj);}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}function _possibleConstructorReturn(self, call) {if (call && (_typeof(call) === "object" || typeof call === "function")) {return call;}return _assertThisInitialized(self);}function _getPrototypeOf(o) {_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {return o.__proto__ || Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function");}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } });if (superClass) _setPrototypeOf(subClass, superClass);}function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);}function _assertThisInitialized(self) {if (self === void 0) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}




// eslint-disable-next-line no-unused-vars
 // IMPORTANT!!

var av = Autodesk.Viewing;
var avp = Autodesk.Viewing.Private;
var namespace = AutodeskNamespace('Autodesk.AEC');
var myExtensionName = 'Autodesk.AEC.Minimap3DExtension';

var LEVEL_EXT = 'Autodesk.AEC.LevelsExtension';
var BIMWALK_EXT = 'Autodesk.BimWalk';

var VISIBILITY_PROP = 'miniMap3D';

// Ensure that all camera matrices are instantly up-to-date.
// This makes sure that compute3DTo2DMatrix() produces always the same resuts, no matter whether we do it before or after rendering.
var updateCameraMatrices = function updateCameraMatrices(camera) {

  // Make sure that camera.rotation is set properly according to pos/target.
  // For the default camera, this usually happens inside tick() function while updating the ToolController.
  av.Navigation.prototype.orient(camera, camera.target, camera.position, camera.up);

  // Make sure that the camera matrices are updated based on latest camera properties.
  // This would happen later in cmdBeginScene() otherwise.
  camera.updateProjectionMatrix();
  camera.updateMatrixWorld();

  // Make sure that worldInverse is up-to-date as well.
  // This would happen later in WebGLRendere.render() otherwise
  camera.matrixWorldInverse.getInverse(camera.matrixWorld);
};

var setTopView = function setTopView(camera, bbox, zMin, zMax, orthoScale) {

  var center = THREE.Box3.prototype.center.call(bbox);

  // set camera pos to upper face center
  camera.position.copy(center);
  camera.position.z = zMax;

  // target distance defines orthoScale, which finally
  // defines the height of the orthoCam frustum in world-space
  camera.target.copy(camera.position);
  camera.target.z -= orthoScale;
  camera.isPerspective = false;

  // set up-vector for view from top
  camera.up.set(0, 1, 0);
  camera.worldup.set(0, 1, 0);

  // Configure near/far to see only zMin/zMax range
  camera.near = 0;
  camera.far = zMax - zMin;

  updateCameraMatrices(camera);
};

// index must be a valid FloorIndex
var getZRange = function getZRange(viewer, index) {

  // Check if we can get floor data
  var LevelExt = viewer.getExtension(LEVEL_EXT);
  var floor = LevelExt && LevelExt.floorSelector && LevelExt.floorSelector.floorData[index];

  // Cut everything above zMid of current floor
  var zMax = floor.zMin + 0.5 * (floor.zMax - floor.zMin);

  // Cut everything below zMid of the floor below
  // (Cutting below zMin keeps stairs to lower floors visible)
  var floorBelow = LevelExt.floorSelector.floorData[index - 1];
  var zMin = floorBelow ? 0.5 * (floorBelow.zMin + floorBelow.zMax) : floor.zMin;

  return { zMin: zMin, zMax: zMax };
};

// Computes a Matrix4 that transforms from 3D model position to
// normalized viewport coords ([-1,1]^2) on the minimap.
var compute3DTo2DMatrix = function compute3DTo2DMatrix(camera, dstMatrix) {
  dstMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
};

// Helper function to smoothen movement of scroll position and zoomScale.
//  @param {number} dist      - distance to move to reach target directly. Must be >=0.
//  @param {number} elapsed   - elapsed time in seconds
//  @param {number} maxSpeed  - maximum allowed distance units per second
//  @param {number} lastSpeed - motion speed according to last cycle (delta / elapsed)
//  @param {number} acc       - acceleration speed (in distance units per s^2)
//  @returns {number} Result is a distance <=dist, which is slowed down if needed for smoother movement.
var motionSmoothing = function motionSmoothing(dist, elapsed, maxSpeed, lastSpeed, acc) {

  // Limit max scroll speed and avoid too sudden acceleration compared to last cycle
  var speed = Math.min(maxSpeed, lastSpeed + acc * elapsed);

  // Slow down with constant deceleration when approaching the target position:
  //
  //   With a constant acceleration a for a time of t seconds, we have:
  //     speed    = t*a
  //     distance = 0.5 * a * t^2
  //
  // To scroll a given distance d with constant acceleration a, the time needed is:
  //   t = sqrt(2*d / a)
  //
  // The speed reached at that point is:
  //   s = a * sqrt(2*d / a)
  //
  // Therefore, s as given above gives us the speed that we must have if distance d
  // to the target if we want to stop at the target given a constant deceleration of a.
  var slowDownSpeed = acc * Math.sqrt(2 * dist / acc);
  speed = Math.min(slowDownSpeed, speed);

  // restrict distance based on computed speed limit
  var maxDist = speed * elapsed;
  return Math.min(dist, maxDist);
};

// int value to string, e.g. 50 => "50px" - to used for style assignments. 
var toPixels = function toPixels(val) {
  return val.toString() + 'px';
};var

Minimap3DExtension = /*#__PURE__*/function (_av$Extension) {_inherits(Minimap3DExtension, _av$Extension);
  function Minimap3DExtension(viewer) {var _this;var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};_classCallCheck(this, Minimap3DExtension);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(Minimap3DExtension).call(this, viewer, options));
    _this.viewer = viewer;
    _this.camera = _this.viewer.navigation.getCamera();

    _this.trackUsage = options.trackUsage;

    _this.cameraMovedCB = _this.onCameraMoved.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.toolChangedCB = _this.onToolChanged.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.geomLoadedCB = _this.onGeomLoaded.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.onVisibilityChangedCB = _this.onVisibilityChanged.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.viewerResizedCB = _this.updateMapSize.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.loadProgressCB = _this.onLoadProgress.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this.extensionLoadCB = _this.onExtensionLoaded.bind(_assertThisInitialized(_assertThisInitialized(_this)));

    _this.levelChangedCB = _this.update.bind(_assertThisInitialized(_assertThisInitialized(_this))); // Level selection may change the current level
    _this.levelChangeListenerRegistered = false;

    _this.onTimerCB = _this.onTimer.bind(_assertThisInitialized(_assertThisInitialized(_this)));

    // Used to sync mapModel with visible model. Not used if client sets the map model (options.useCustomModel)
    _this.visibleModelsChanged = _this.setDefaultMapModel.bind(_assertThisInitialized(_assertThisInitialized(_this)));

    _this.draggingPlayerPosition = false;

    // The actual map resolution is chosen based on model bbox size in meters.
    _this.minMapImageSize = 300;
    _this.maxMapImageSize = 2048;

    // Used to determine required map resolution
    _this.pixelsPerMeter = 10;

    // Map widget size
    _this.mapWidgetWidth = 300;
    _this.mapWidgetHeight = 300;

    // Map image size (may exceed mapWidget)
    _this.mapImageWidth = 300;
    _this.mapImageHeight = 300;

    // Map image size after applyign zoomScale
    _this.scaledImageWidth = 0;
    _this.scaledImageHeight = 0;

    // Params for choosing mapWidget size based on canvas size
    _this.relMapWidgetSizeLongEdge = 0.20; // Restrict to max 20% of the canvas along the longer axis with
    _this.relMapWidgetSizeShortEdge = 0.25; // Restrict to max 30% of the canvas along the shorter axis (more tolerance here, to keep map useful for widescreen)
    _this.minMapWidgetSize = 100; // if the map gets too small, we hide it.

    // Scale-factor in [minScale,1] for zoom-out. Auto-updated based on zoomLevel
    //  - Default: 1.0 (= full map resolution).
    //  - minScale is the smallest scale necessary to fit the whole map into the mapWidget
    _this.zoomScale = 1.0;

    // zoomLevel:
    //  0 = full resolution
    //  1 = Half resolution
    //  ...
    _this.targetZoomLevel = 0; // the one that we set directly
    _this.zoomLevel = 0; // animated to trace targetZoomLevel

    // params for smoothing zoom
    _this.zoomSpeed = 6.0; // zoom-levels per second
    _this.zoomAcc = 16.0; // zoom-levels per second^2
    _this.lastZoomSpeed = 0;

    // The visible section of the full map image is defined by
    //   min=(scrollPos.x, scrollXPos.y)
    //   max=(scrollPos.x + mapWidgetWidth, scrollPos.y + mapWidgetHeight)
    //
    // scroll positions are defined within the scaled mapImage, i.e. after scaling by zoomScale.
    _this.scrollPos = new THREE.Vector2();

    // The scrolling follows the player position and tries to bring it to the center. But it is filtered
    // by maxSpeed - otherwise it would suddenly jump after moving the playerposition.
    _this.targetScrollPos = new THREE.Vector2();

    _this.maxScrollSpeed = 500; // Maximum allowed scrollspeed in pixels per second
    _this.maxScrollAcc = 900; // Maximum allowed acceleration/deceleration in pixels/s^2

    // Track last applied scroll-speed (in ms) to restrict the acceleration.
    _this.lastScrollSpeed = 0;

    // Matrix to convert 3D model positions to relative coords on minimap (in [-1, 1]).
    // Will be set on minimap creation.
    _this.mapMatrix = new THREE.Matrix4();
    _this.mapMatrixInverse = new THREE.Matrix4();

    // guid of the level for which the current map is valid
    _this.currentLevelIndex = undefined;

    // flag to indicate if an (async) map update is in progress
    _this.updatingMap = false;

    _this.initWidgets();

    // Indicates if..
    _this.mapValid = false; // widget is setup with a valid map
    _this.placeholderShown = false; // widget is setup to show map creation progress

    // Map from levelIndex to map image blob string
    _this.mapCache = {};

    _this.tool = new _MinimapTool_js__WEBPACK_IMPORTED_MODULE_0__["default"](_assertThisInitialized(_assertThisInitialized(_this)), _this.trackUsage);

    // player-position in map-pixels. independent of scrolling
    _this.playerPos = new THREE.Vector2();
    _this.playerAngle = 0.0; // view rotation angle in degrees (0 = up)

    // The models from which we compute the map. By default, we use all visible ones
    _this.mapModels = null;

    // Used to suppress auto-scroll while we are dragging the player avatar on the map
    _this.autoScrollLocked = false;

    // Cache the fuzzy-box per model id
    _this.modelIdToFuzzyBox = [];

    // Only used for map updates
    _this.mapModelBox = new THREE.Box3();

    // Indicates that mapModels have been specified, but we are waiting for them to finish loading.
    _this.isLoading = false;

    _this.visible = false;return _this;
  }_createClass(Minimap3DExtension, [{ key: "setMinimapVisible", value: function setMinimapVisible(

    visible) {var _this2 = this;

      this.visible = visible;

      // If the minimap widget is just showing a progress bar, we don't show the player avatar
      var isProgress = this.mapWidget.mapImage === this.placeholderDiv;

      // Trigger css anim. Note that doing this synchronously would skip the animation.
      window.requestAnimationFrame(function () {
        if (visible) {
          _this2.mapWidget.classList.add('visible');
          _this2.viewer.displayViewCube(false, false);
        } else {
          _this2.mapWidget.classList.remove('visible');
        }

        // Show player widget only if an actual map is displayed
        if (visible && !isProgress) {
          _this2.playerPositionWidget.classList.add('visible');
        } else {
          _this2.playerPositionWidget.classList.remove('visible');
        }
      });

      // Make sure that we reserve space for the minimap as soon as we start fade-in
      this.updateBimWalkInfoButtonPos();
    }

    // Check if minimap is enabled in viewer config. Note that this does not necessarily mean that it is visible,
    // e.g., BIMWalk may not be active.
  }, { key: "isEnabled", value: function isEnabled() {
      return this.viewer.prefs.get(VISIBILITY_PROP);
    } }, { key: "onVisibilityChanged", value: function onVisibilityChanged(

    visible) {
      this.viewer.prefs.set(VISIBILITY_PROP, visible);
      this.update();
    }

    // Placeholder widget is displayed when a map computation is in progress. It contains a text "Computing map for.." and a progress bar.
  }, { key: "initPlaceholderWidget", value: function initPlaceholderWidget() {

      // Placeholder widget used if map computation is in progress
      this.placeholderDiv = document.createElement('div');
      this.placeholderDiv.className = 'minimap-placeholder';
      this.placeholderDiv.style.width = toPixels(this.mapWidgetWidth);
      this.placeholderDiv.style.height = toPixels(this.mapWidgetHeight);

      // Vertically centered placeholder child containing text and progress bar
      var progressParent = document.createElement('div');
      progressParent.className = 'minimap-progressWidget';
      this.placeholderDiv.appendChild(progressParent);

      // add progress text
      this.progressText = document.createElement('div');
      this.progressText.className = 'minimap-progressText';
      progressParent.appendChild(this.progressText);

      // add progress bar
      this.progressDiv = document.createElement('progress');
      this.progressDiv.className = 'minimap-progress';
      this.progressDiv.setAttribute('max', 100);
      progressParent.appendChild(this.progressDiv);
    } }, { key: "initWidgets", value: function initWidgets()

    {var _this3 = this;
      // Div showing the minimap
      this.mapWidget = document.createElement('div');
      this.mapWidget.className = 'minimap3D';
      this.mapWidget.style.width = toPixels(this.mapWidgetWidth);
      this.mapWidget.style.height = toPixels(this.mapWidgetHeight);

      // Child-Div of MapWidget to represent current camera position and view direction on minimap (child of Minimap div)
      this.playerPositionWidget = document.createElement('div');
      this.playerPositionWidget.className = 'player-widget';
      this.mapWidget.appendChild(this.playerPositionWidget);

      // Sub-widget to represent view direction in minimap
      this.playerFrustumWidget = document.createElement('div');
      this.playerFrustumWidget.className = 'player-frustum';
      this.playerPositionWidget.appendChild(this.playerFrustumWidget);

      // By default, setting left/top to posX/posY would move the top-left corner of the frustum
      // widget to that position. We want to have the tip of the camera there.
      // Note that the offset may change depending on the border sizes in player-widget css class.
      this.playerPositionWidget.anchorX = 20; // =.player-widget.border-left
      this.playerPositionWidget.anchorY = 40; // =.player-widget.border-top

      // Filled circle at camera position
      var filledCircle = document.createElement('div');
      filledCircle.className = 'player-position-fill';
      this.playerPositionWidget.appendChild(filledCircle);
      this.playerPositionWidget.posCircle = filledCircle;

      this.initPlaceholderWidget();

      // hidden until level map is set
      this.setMinimapVisible(false);

      // Whenver the mapWidget finished fading in or out, we might need to re-adjust
      // the position of the annoying Info button of BimWalk to avoid overlapping.
      this.mapWidget.addEventListener('transitionend', function () {return _this3.updateBimWalkInfoButtonPos();});
    } }, { key: "load", value: function load()

    {
      this.loaded = true;

      this.trackUsage && this.trackUsage({
        minimap_loaded: this.loaded });


      // choose widget size based on current canvas size
      this.updateMapSize();

      this.viewer.container.appendChild(this.mapWidget);

      this.tool.activate();

      this.viewer.addEventListener(av.CAMERA_CHANGE_EVENT, this.cameraMovedCB);
      this.viewer.addEventListener(av.TOOL_CHANGE_EVENT, this.toolChangedCB);
      this.viewer.addEventListener(av.GEOMETRY_LOADED_EVENT, this.geomLoadedCB);
      this.viewer.addEventListener(av.VIEWER_RESIZE_EVENT, this.viewerResizedCB);
      this.viewer.addEventListener(av.PROGRESS_UPDATE_EVENT, this.loadProgressCB);
      this.viewer.addEventListener(av.EXTENSION_LOADED_EVENT, this.extensionLoadCB);

      this.updateFloorSelectHandler();

      // Always compute the map from "current model" - unless the client app specifies the mapModel explicitly.
      if (!this.options.useCustomModel) {

        // If a 3D model added before loading the extension, use it right now.
        this.setDefaultMapModel();

        this.viewer.addEventListener(av.MODEL_ADDED_EVENT, this.visibleModelsChanged);
        this.viewer.addEventListener(av.MODEL_REMOVED_EVENT, this.visibleModelsChanged);
      }

      // Update scrolling on timer
      this.requestTimer();

      return true;
    } }, { key: "unload", value: function unload()

    {
      this.loaded = false;

      // Avoid crash in case the client app hijacked the mapWidget to add it somewhere else
      if (this.viewer.container.contains(this.mapWidget)) {
        this.viewer.container.removeChild(this.mapWidget);
      }

      this.tool.deactivate();

      this.viewer.removeEventListener(av.CAMERA_CHANGE_EVENT, this.cameraMovedCB);
      this.viewer.removeEventListener(av.TOOL_CHANGE_EVENT, this.toolChangedCB);
      this.viewer.removeEventListener(av.GEOMETRY_LOADED_EVENT, this.geomLoadedCB);
      this.viewer.removeEventListener(av.VIEWER_RESIZE_EVENT, this.viewerResizedCB);
      this.viewer.removeEventListener(av.PROGRESS_UPDATE_EVENT, this.loadProgressCB);
      this.viewer.removeEventListener(av.EXTENSION_LOADED_EVENT, this.extensionLoadCB);

      this.updateFloorSelectHandler();

      if (!this.options.useCustomModel) {
        this.viewer.removeEventListener(av.MODEL_ADDED_EVENT, this.visibleModelsChanged);
        this.viewer.removeEventListener(av.MODEL_REMOVED_EVENT, this.visibleModelsChanged);
      }

      // Stop scrolling timer interrupts
      this.cancelTimer();

      // Make sure that we don't leak models
      return true;
    } }, { key: "onExtensionLoaded", value: function onExtensionLoaded(

    e) {
      if (e.extensionId === LEVEL_EXT) {
        this.updateFloorSelectHandler();
      }
    }

    // Make sure that we detect Floor-select events as long as Minimap and LevelsExt are both loaded.
  }, { key: "updateFloorSelectHandler", value: function updateFloorSelectHandler() {

      var levelExt = this.viewer.getExtension(LEVEL_EXT);
      if (!levelExt) {
        // We will try again later on extension load
        return;
      }
      var registered = this.levelChangeListenerRegistered;
      if (!registered && this.loaded) {
        levelExt.floorSelector.addEventListener(Autodesk.AEC.FloorSelector.CURRENT_FLOOR_CHANGED, this.levelChangedCB);
        this.levelChangeListenerRegistered = true;
      } else if (registered && !this.loaded) {
        levelExt.floorSelector.removeEventListener(Autodesk.AEC.FloorSelector.CURRENT_FLOOR_CHANGED, this.levelChangedCB);
        this.levelChangeListenerRegistered = false;
      }
    }

    // Move/Rotate player-position widget according to player position and angle.
  }, { key: "updatePlayerWidget", value: function updatePlayerWidget() {

      // apply zoomScale and scroll-position offset
      var posX = this.playerPos.x * this.zoomScale - this.scrollPos.x;
      var posY = this.playerPos.y * this.zoomScale - this.scrollPos.y;

      var style = this.playerPositionWidget.style;
      style.left = toPixels(posX - this.playerPositionWidget.anchorX);
      style.top = toPixels(posY - this.playerPositionWidget.anchorY);

      // rotate frustum shape
      this.playerFrustumWidget.style.transform = "rotate(".concat(this.playerAngle, "deg)");
    }

    // Adjust target scroll-position based on current player position
  }, { key: "computeTargetScrollPosition", value: function computeTargetScrollPosition() {

      // If player is outside, we stop tracing the player and show the whole map
      if (this.isOutside()) {
        this.targetScrollPos.x = 0;
        this.targetScrollPos.y = 0;
        return;
      }

      // compute player position within scaled map
      var px = this.playerPos.x * this.zoomScale;
      var py = this.playerPos.y * this.zoomScale;

      // Try to scroll player into map center
      this.targetScrollPos.x = px - 0.5 * this.mapWidgetWidth;
      this.targetScrollPos.y = py - 0.5 * this.mapWidgetHeight;
    }

    // recompute this.playerPos and this.playerAngle according to current 3D camera
  }, { key: "computePlayerPosition", value: function computePlayerPosition() {

      // If this call happens during async map update, don't set player position.
      // Otherwise, it would just reflect the camera pos during map update.
      if (this.updatingMap) {
        return;
      }

      // convert camera pos to miniMap pix coords
      var pos3D = this.viewer.impl.camera.position;
      var pos2D = this.worldPosToMapPixels(pos3D);

      // convert camera target to miniMap
      var target3D = this.viewer.impl.camera.target;
      var target2D = this.worldPosToMapPixels(target3D);

      this.playerPos.copy(pos2D);
      this.playerAngle = this.computeAngle(pos2D, target2D);
    }

    // Apply scrolling using css
  }, { key: "applyScrolling", value: function applyScrolling() {
      // Note that mapImage may also exist, but just be the placeholder - which should not be scrolled.
      if (this.mapValid) {
        // set image size based on map resolution and zoomScale
        var style = this.mapWidget.mapImage.imageElement.style;
        style.width = toPixels(this.scaledImageWidth);
        style.height = toPixels(this.scaledImageHeight);

        // set scroll position
        this.mapWidget.mapImage.style.left = toPixels(-this.scrollPos.x);
        this.mapWidget.mapImage.style.top = toPixels(-this.scrollPos.y);
      }
    }

    // Immediately set scrolling to target position (based on player pos)
  }, { key: "resetScrolling", value: function resetScrolling() {
      this.zoomLevel = this.targetZoomLevel; // skip any ongoing zoom-motion
      this.computeTargetScrollPosition();
      this.scrollPos.copy(this.targetScrollPos);
      this.applyScrolling();
    }

    // Adjust scrolling and player position widget based on current 3D camera
    //  @param {number} elapsed - elapsed time in seconds
  }, { key: "updateScrolling", value: function updateScrolling(elapsed) {

      // Compute scroll position to follow the player
      if (this.autoScrollLocked) {
        return;
      }

      this.computeTargetScrollPosition();

      // get vector and distance towards targetPos
      var delta = this.targetScrollPos.clone().sub(this.scrollPos);
      var dist = delta.length();

      // If distance is below a pixel, there is nothing to do
      if (dist < 0.5) {
        return;
      }

      // apply scroll-speed limit
      var newDist = motionSmoothing(dist, elapsed, this.maxScrollSpeed, this.lastScrollSpeed, this.maxScrollAcc);
      delta.multiplyScalar(newDist / dist);

      // move player pos
      this.scrollPos.add(delta);

      // Update player avatar (based on player pos + scroll position)
      this.updatePlayerWidget();
      this.applyScrolling();

      // track applied scroll speed
      if (elapsed) {
        this.lastScrollSpeed = newDist / elapsed;
      }
    }

    // Returns true if all mapModels are ready for map rendering
  }, { key: "mapModelsReady", value: function mapModelsReady() {
      if (!this.mapModels) {
        return false;
      }

      for (var i = 0; i < this.mapModels.length; i++) {
        var model = this.mapModels[i];
        if (!model.isLoadDone()) {
          // We need to wait until model finished loading
          return false;
        }
      }
      return true;
    }

    // Returns a floor object {index, name}
  }, { key: "getCurrentLevel", value: function getCurrentLevel() {
      var levelExt = this.viewer.getExtension(LEVEL_EXT);
      if (!levelExt) {
        return;
      }

      // If a level is selected, use that one and ignore camera z
      var fs = levelExt.floorSelector;
      var level = fs.floorData[fs.currentFloor];
      if (level) {
        return level;
      }

      // No floor selected => determine based on camera z
      return levelExt._mapCameraToLevel();
    }

    // Makes sure that map shows an image of the current level.
  }, { key: "updateMapImage", value: function updateMapImage() {

      // Avoid mapUpdate if another one is in progress, extension was unloaded, or model is not ready
      if (this.updatingMap || !this.loaded || !this.mapModelsReady()) {
        return;
      }

      // Choose for which level we want to display the map
      var level = this.getCurrentLevel();
      if (!level) {
        return;
      }

      // We can skip the update if the level didn't change (unless we are currently just showing a placeholder)
      var index = level.index;
      if (this.currentLevelIndex === index && this.mapValid) {
        // no map update needed
        return;
      }

      if (Number.isInteger(index)) {
        // set index only if defined
        this.currentLevelIndex = index;
      }

      // Create or activate map for that level
      var imageUrl = this.mapCache[this.currentLevelIndex];
      if (imageUrl) {
        // We visited that level before => reuse map image
        this.activateMap(imageUrl, level.name);
      } else {
        this.createMinimap(this.currentLevelIndex, level.name);
      }
    } }, { key: "bimWalkActive", value: function bimWalkActive()

    {
      // Minimap is only shown in first-person mode
      var bimWalk = this.viewer.getExtension(BIMWALK_EXT);
      return bimWalk && bimWalk.tool && bimWalk.tool.active;
    } }, { key: "onCameraMoved", value: function onCameraMoved()

    {
      this.update();
    } }, { key: "update", value: function update()

    {

      var wasVisible = this.visible;

      if (!this.isEnabled() || !this.bimWalkActive()) {
        this.setMinimapVisible(false);
        return;
      }

      // If geom is not loaded, wait until update() is triggered again by the geomLoad event
      if (!this.mapModelsReady()) {

        if (!this.mapModels) {
          this.setMinimapVisible(false);
        } else {
          // We are waiting for models to load => show load progress.
          this.showLoadProgress();
        }
        return;
      }

      // If we get here, we are not waiting for any model loading anymore.
      this.isLoading = false;

      this.setMinimapVisible(true);
      this.computePlayerPosition();
      this.updatePlayerWidget();
      this.updateMapImage();

      // If the camera is outside the map range, always zoom out to full map
      if (this.isOutside()) {
        this.targetZoomLevel = this.getMinZoomLevel();
      }

      if (!wasVisible) {
        this.resetScrolling();
      }
    } }, { key: "onToolChanged", value: function onToolChanged(

    tool) {var _this4 = this;

      // we temporarily disable/enable BimWalk ourselves during map update
      if (this.updatingMap) {
        return;
      }

      if (!tool.toolName === 'bimwalk') {
        return;
      }

      // Note: Activating the map might trigger a map update. If this starts synchronously right now,
      //       some BIMWalk code after this event would affect the camera and switch it back to perspective.
      // TODO: Think about if there is a cleaner way to avoid tools from affecting the snapshots (without having to switch BIMWalk off)
      setTimeout(function () {return _this4.update();}, 10);
    } }, { key: "onGeomLoaded", value: function onGeomLoaded(

    e) {
      // If the mapModel just finished loading and minimap is wanted, make sure that we create & show it
      this.update();
    }

    // Sets the progress widget as current map
  }, { key: "showProgressWidget", value: function showProgressWidget() {

      // Do nothing if already visible
      var isShown = this.mapWidget.mapImage === this.placeholderDiv;
      if (isShown) {
        return;
      }

      // Remember previous mapImage (if any)
      this.clearMapImage();

      // Show placeholder
      this.mapWidget.appendChild(this.placeholderDiv);

      // fade-in placeholder
      this.placeholderDiv.style.opacity = 0.0;
      this.fadeWidgetOpacity(this.placeholderDiv, 1.0);
      this.updateProgressWidget(0);

      // Make placeholder the new mapImage - so that it will be replaced and faded once
      // the map image is ready
      this.mapWidget.mapImage = this.placeholderDiv;

      this.placeholdershown = true;
      this.setMinimapVisible(true);
    } }, { key: "setProgressText", value: function setProgressText(

    text) {
      this.progressText.innerHTML = text;
    } }, { key: "updateProgressWidget", value: function updateProgressWidget(

    percent) {
      this.progressDiv.setAttribute('value', percent);
    }

    // Called if mapModels have been specified, but are still loading
  }, { key: "showLoadProgress", value: function showLoadProgress() {
      this.showProgressWidget();
      this.setProgressText('Loading models...');
      this.setMinimapVisible(true);
      this.isLoading = true;
    }

    // Compute percent of loaded fragments for all models that we are waiting for to compute the map
  }, { key: "getLoadProgress", value: function getLoadProgress() {
      var loaded = 0;
      var total = 0;
      var numModels = this.mapModels ? this.mapModels.length : 0;
      for (var i = 0; i < numModels; i++) {
        var model = this.mapModels[i];

        // Note: Progress tracking other formats would require some extra work here.
        if (!model.isOTG()) {
          continue;
        }

        var data = model.getData();
        loaded += data.fragsLoaded;
        total += data.metadata.stats.num_fragments;
      }
      return total ? Math.floor(100 * loaded / total) : 0;
    } }, { key: "onLoadProgress", value: function onLoadProgress()

    {
      // Progress events are only relevant while waiting for model load
      if (!this.isLoading) {
        return;
      }

      var progress = this.getLoadProgress();
      this.updateProgressWidget(progress);
    }

    // Fade-out current map image and removes it after fading
  }, { key: "clearMapImage", value: function clearMapImage() {var _this5 = this;

      var oldImage = this.mapWidget.mapImage;
      var oldLabel = this.mapWidget.floorLabel;
      if (!oldImage) {
        return;
      }

      this.mapWidget.mapImage = null;
      this.mapWidget.floorLabel = null;

      // Make sure that mapImage is removed after fadeout (if still not in use)
      var onFadeDone = function onFadeDone() {
        // Note: oldImage may be reused meanwhile (happens for placeholderDiv).
        // Adding the same child a second time has no effect, but we must not remove it in that case.
        var isActive = _this5.mapWidget.mapImage === oldImage;
        if (!isActive && _this5.mapWidget.contains(oldImage)) {
          _this5.mapWidget.removeChild(oldImage);
        }
      };

      // invoke fade-out
      this.fadeWidgetOpacity(oldImage, 0.0, onFadeDone);

      // fade-out label too (if any)
      if (oldLabel) {
        this.fadeWidgetOpacity(oldLabel, 0.0, function () {return _this5.mapWidget.removeChild(oldLabel);});
      }

      // update state flags: there is nothing to display
      this.mapValid = false;
      this.placeholderShown = false;
    } }, { key: "fadeWidgetOpacity", value: function fadeWidgetOpacity(

    widget, targetValue, onFadeDone) {

      var FadeDuration = 0.7;

      if (widget.fadeAnim) {
        widget.fadeAnim.stop();
        widget.fadeAnim = null;
      }

      var startVal = widget.style.opacity;
      var onTimer = function onTimer(t) {
        t = avp.smootherStep(t);
        widget.style.opacity = avp.lerp(startVal, targetValue, t);
      };
      widget.fadeAnim = avp.fadeValue(0, 1, FadeDuration, onTimer, onFadeDone);
    } }, { key: "activateMap", value: function activateMap(

    imageUrl, levelName) {

      // Remove outdated image
      this.clearMapImage();

      // Create new div with map
      this.mapWidget.mapImage = document.createElement('div');
      this.mapWidget.mapImage.className = 'mapContainer';
      this.mapWidget.mapImage.innerHTML = "<img class=\"mapImage\" src=\"".concat(imageUrl, "\">");
      this.mapWidget.mapImage.style.width = toPixels(this.scaledImageWidth);
      this.mapWidget.mapImage.style.height = toPixels(this.scaledImageHeight);
      this.mapWidget.appendChild(this.mapWidget.mapImage);

      // Get imageElement defined in innerHTML above.
      // It would be a bit easier to avoid the parent element and create mapWidget as image directly,
      // but this always failed to load the blobl url (not sure why).
      this.mapWidget.mapImage.imageElement = this.mapWidget.mapImage.children[0];

      // attach floor name label to map image
      var floorLabel = document.createElement('div');
      floorLabel.className = 'floorNameLabel';
      this.mapWidget.appendChild(floorLabel);
      this.mapWidget.floorLabel = floorLabel;

      // add text to label
      var floorText = document.createElement('div');
      floorText.className = 'floorText';
      floorText.textContent = levelName;
      floorLabel.appendChild(floorText);

      // Fade-in new map image
      this.mapWidget.mapImage.style.opacity = 0;
      this.fadeWidgetOpacity(this.mapWidget.mapImage, 1.0);
      this.fadeWidgetOpacity(this.mapWidget.floorLabel, 1.0);

      this.mapWidget.appendChild(this.playerPositionWidget);

      this.mapValid = true;

      this.computePlayerPosition();
      this.resetScrolling();
      this.updatePlayerWidget();
      this.setMinimapVisible(true);
    } }, { key: "cancelMapUpdate", value: function cancelMapUpdate()

    {
      if (this.screenShotInProgress) {
        this.screenShotInProgress.stop();
        this.updatingMap = false;
      }
    } }, { key: "getFuzzyBox", value: function getFuzzyBox()

    {

      this.mapModelBox.makeEmpty();
      if (!this.mapModels) {
        return;
      }

      // sum up fuzzy boxes of all map models
      for (var i = 0; i < this.mapModels.length; i++) {

        var model = this.mapModels[i];

        // get bbox from cache if possible
        var bbox = this.modelIdToFuzzyBox[model.id];
        if (bbox) {
          return bbox;
        }

        // compute fuzzybox and add it to cache
        bbox = Object(_FuzzyBox_js__WEBPACK_IMPORTED_MODULE_1__["default"])(model);
        this.modelIdToFuzzyBox[model.id] = bbox;

        this.mapModelBox.union(bbox);
      }
      return this.mapModelBox;
    }

    // Create a map based on a (valid) level index from FloorSelector
  }, { key: "createMinimap", value: function createMinimap(levelIndex, levelName) {var _this6 = this;

      // Replace current map by progress widget
      this.showProgressWidget();
      this.setProgressText('Creating map for:<br><b>' + levelName);

      var bbox = this.getFuzzyBox();
      var diag = bbox.size();

      // If multiple models are shown together, they must have identical unit scale. Therefore, we can get the scale from any model.
      var unitToMeter = this.mapModels[0].getUnitScale();

      // Expand map scope by a few meters of margin
      var marginInMeters = 1;
      var offset = 2 * marginInMeters / unitToMeter;
      diag.x += offset;
      diag.y += offset;

      // compute required resolution
      var resX = diag.x * unitToMeter * this.pixelsPerMeter;
      var resY = diag.y * unitToMeter * this.pixelsPerMeter;

      // Orthoscale must be set to the full world-space height that we want to capture.
      var orthoScale = diag.y;

      // If both width and height are below minMapSize, scale down to fill the mapWidget
      if (resX < this.minMapImageSize && resY < this.minMapImageSize) {
        var smallerSide = Math.min(resX, resY);
        var factor = this.minMapImageSize / smallerSide;
        resX *= factor;
        resY *= factor;
      }

      // If any of the sides exceeds max mapImageSize, scale down to keep them within
      var maxXY = Math.max(resX, resY);
      if (maxXY > this.maxMapImageSize) {
        var _factor = this.maxMapImageSize / maxXY;
        resX *= _factor;
        resY *= _factor;
      }

      // After the steps above, we know for sure that width and height are both within maxImageSize and
      // at least one (width or height) is >= minImageSize.
      // If only one of the two is too small, we have to change the aspect ratio and extend the world-space
      // map scope.
      if (resX < this.minMapImageSize) {
        // Adding pixels will also change the camera's aspect ratio => mapped scope will extended in x automatically
        resX = this.minMapImageSize;
      } else if (this.mapImageHeight < this.minMapImageSize) {
        // To extend mapped scope in y, we have to "zoom out" a bit. Just increasing image-height would increase the mapping
        // scale, so that we wouldn't capture the full x-extend of the map scope anymore.
        var oldHeight = this.mapImageHeight;
        resY = this.minMapImageSize;

        // This increases the camera frustum y-extend in world-space. Effect is:
        //  - Increase frustum along y-direction
        //  - Keep x-extent of camera frustum unaffected by modified camera aspect
        orthoScale *= resY / oldHeight;
      }

      // remember map sizes
      this.mapImageWidth = resX;
      this.mapImageHeight = resY;
      this.scaledImageWidth = this.zoomScale * resX;
      this.scaledImageHeight = this.zoomScale * resY;

      // create new top-view camera
      var cam = new av.UnifiedCamera(this.mapImageWidth, this.mapImageHeight);
      var zRange = getZRange(this.viewer, levelIndex);
      setTopView(cam, bbox, zRange.zMin, zRange.zMax, orthoScale);

      // Remember transform from model to map and back
      compute3DTo2DMatrix(cam, this.mapMatrix);
      this.mapMatrixInverse.getInverse(this.mapMatrix);

      this.updatingMap = true;

      var onScreenshotDone = function onScreenshotDone(imageUrl) {

        _this6.updatingMap = false;
        _this6.screenShotInProgress = null;

        // add map to cache for later reuse
        _this6.mapCache[levelIndex] = imageUrl;

        // activate the new map (or another one if the user changed to another floor meanwhile)
        _this6.updateMapImage();
      };

      // Use another polygon offset setting for the snapshot. Otherwise, edges are mostly missing in
      // ortho-vies exactly from above.
      //
      // TODO: It's some performance waste to do that back-and-forth change on all materials. It would be nice
      //       if we could find a more elegant solution here. E.g., setting polygonOffset on the lines instead - but
      //       this didn't seem to work.
      var mats = this.viewer.impl.getMaterials();
      var poEnabled;
      var poFactor;
      var poUnits;
      var applyCustomPolygonOffset = function applyCustomPolygonOffset() {
        // remember main polygonOffset settings
        poEnabled = mats.getPolygonOffsetOn();
        poFactor = mats.getPolygonOffsetFactor();
        poUnits = mats.getPolygonOffsetUnits();

        // apply custom polygon offset
        mats.togglePolygonOffset(true, 1.0, 5.0);
      };
      var revertCustomPolygonOffset = function revertCustomPolygonOffset() {
        // revert main-canvas polygonOffset
        mats.togglePolygonOffset(poEnabled, poFactor, poUnits);
      };

      // make empty map-space semi-transparent
      var renderConfig = this.viewer.impl.renderer().getConfig();
      renderConfig.clearAlpha = 0.3;

      // Make sure that Minimap creation is not affected by current fragment modifications in main view (e.g. setting frags off or ghosted)        
      var fragOptions = {
        isFragVisible: function isFragVisible() {return true;}, // force fragment ghosting off
        isFragOff: function isFragOff() {return false;} // avoid frags to be excluded
      };

      var options = {
        camera: cam,
        onProgress: function onProgress(percent) {return _this6.updateProgressWidget(percent);},
        beforeRender: applyCustomPolygonOffset,
        afterRender: revertCustomPolygonOffset,
        renderConfig: renderConfig,
        models: this.mapModels,
        fragOptions: fragOptions,
        excludeCutPlanes: true, // Make map content independent of current cutplane states, e.g. FloorSelector or SectionTool
        excludeThemingColors: true };

      this.screenShotInProgress = this.viewer.impl.getScreenShotProgressive(this.mapImageWidth, this.mapImageHeight, onScreenshotDone, options);
    }

    // Transform 3D model position to pixel-space position on full MiniMap. Indepdent of scroll-position.
  }, { key: "worldPosToMapPixels", value: function worldPosToMapPixels(pos3D) {
      var p = pos3D.clone().applyProjection(this.mapMatrix);
      var res = new THREE.Vector2(
      (p.x + 1) / 2 * this.mapImageWidth,
      (-p.y + 1) / 2 * this.mapImageHeight);

      return res;
    }

    // Convert minimap pixel coords (+ world-z) to 3D world position. Minimap pixels are absolute, i.e. not affected by scrolling.
  }, { key: "mapPixelsToWorld", value: function mapPixelsToWorld(posX, posY, zWorld) {
      // convert pixels to normalized viewport coords in [-1,1]
      var vx = 2 * (posX / this.mapImageWidth) - 1.0;
      var vy = 2 * (posY / this.mapImageHeight) - 1.0;

      // Beware of the annoying y-flip
      var p = new THREE.Vector3(vx, -vy, 0.0).applyProjection(this.mapMatrixInverse);
      p.z = zWorld;
      return p;
    }

    // Compute rotation angle for camera view-cone on map.
    //  @param {THREE.Vector2} pos    - camera position     in minimap pixel space
    //  @param {THREE.Vector2} target - camera target point in minimap pixel space
    //  @returns {number}  Rotation angle in degrees to transform a originally up-facing div located
    //                     in a way that it points towards (p2-p1).
  }, { key: "computeAngle", value: function computeAngle(pos, target) {
      var dx = target.x - pos.x;
      var dy = target.y - pos.y;
      var angle = Math.atan2(dy, dx) * 180 / Math.PI;

      // atan measures the angle to the x-axis, but we want it to work for divs originally aligned with +y.
      angle += 90;

      return angle;
    }

    // Default behavior: Use the (first) visible 3D model for the map
  }, { key: "setDefaultMapModel", value: function setDefaultMapModel() {

      var models = this.viewer.getVisibleModels();
      var is3d = function is3d(m) {return m.is3d();};
      if (models && models.every(is3d)) {
        this.setMapModels(models);
      } else {
        this.setMapModels(null);
      }
    }

    // Set/Change model for which we generate the map
  }, { key: "setMapModels", value: function setMapModels(models) {var _this7 = this;

      // If the models are the same, there is nothing to do
      if (!models && !this.mapModels) {
        return;
      }

      // Model count is usually small enough, otherwise we would need to avoid O(modelCount^2) here.
      var modelKnown = function modelKnown(m) {return _this7.mapModels.indexOf(m) >= 0;};
      if (models && this.mapModels && models.length === this.mapModels.length && models.every(modelKnown)) {
        return;
      }

      // We don't want to distinguish null and empty array, so we always set null if there is no model.
      // Note that we better copy the array than sharing them - to make sure that they are not changed outside our control.
      this.mapModels = models && models.length ? models.slice() : null;

      // Cancel any running map creation if the model changed
      this.cancelMapUpdate();

      // Clear cached maps and invalidate current one
      this.mapCache = {};
      this.mapValid = false;
      this.update();
    } }, { key: "updateSettings", value: function updateSettings(

    panel, tab) {
      // add toggle to the hypermodeling tab of the viewer settings
      if (panel && !panel.showMinimapChkBoxId) {
        panel.showMinimapChkBoxId = panel.addCheckbox(
        tab,
        "Show 3D mini-map",
        "Toggles availability of the 3D mini-map when using first person mode",
        true,
        this.onVisibilityChangedCB,
        VISIBILITY_PROP);

      }
    } }, { key: "requestTimer", value: function requestTimer()

    {
      this.animTimerId = window.requestAnimationFrame(this.onTimerCB);
    } }, { key: "cancelTimer", value: function cancelTimer()

    {
      window.cancelAnimationFrame(this.animTimerId);
    } }, { key: "onTimer", value: function onTimer()

    {
      // get elapsed time in seconds
      var curTime = performance.now();
      var elapsed = curTime - this.lastTimer;
      this.lastTimer = curTime;

      // get time in seconds and restrict it (if we got no events for a while)
      elapsed = Math.min(elapsed || 0, 1000);
      elapsed /= 1000;

      this.updateZoomScale(elapsed);
      this.updateScrolling(elapsed);

      this.requestTimer();
    } }, { key: "setZoomScale", value: function setZoomScale(

    scale) {
      var oldScale = this.zoomScale;
      this.zoomScale = scale;

      // update scaled image size
      this.scaledImageWidth = this.mapImageWidth * this.zoomScale;
      this.scaledImageHeight = this.mapImageHeight * this.zoomScale;

      // recompute target scroll position based on player position
      this.computeTargetScrollPosition();

      var zoomOut = scale < oldScale;
      if (zoomOut) {

        // By default, we keep the player position constant on the map position when zooming out.
        // But if the player is outside, we use a non-directed zoom and use the point at widget center as focus.
        var focusX = this.playerPos.x;
        var focusY = this.playerPos.y;
        if (this.isOutside()) {
          // Chose position on the map that corresponds to the current
          // widget center 
          focusX = (this.scrollPos.x + this.mapWidgetWidth / 2) / oldScale;
          focusY = (this.scrollPos.y + this.mapWidgetHeight / 2) / oldScale;
        }

        // compute previous player position relative to widget
        var px = focusX * oldScale - this.scrollPos.x;
        var py = focusY * oldScale - this.scrollPos.y;

        // compute new scroll position in a way that the relative player-widget position keeps the same
        this.scrollPos.x = focusX * this.zoomScale - px;
        this.scrollPos.y = focusY * this.zoomScale - py;
      } else {
        // zoom-in: We choose a sub-region of the currently visible map region. We choose it in a way that
        // it gets as close to the targetScrollPos as possible.

        // compute region within the zoomed-in map that corresponds to the previously visible one.
        var rescale = scale / oldScale;
        var regionMinX = this.scrollPos.x * rescale;
        var regionMinY = this.scrollPos.y * rescale;
        var regionWidth = this.mapWidgetHeight * rescale;
        var regionHeight = this.mapWidgetHeight * rescale;

        // compute max-scroll position to keep within that region
        var maxScrollX = regionMinX + regionWidth - this.mapWidgetWidth;
        var maxScrollY = regionMinY + regionHeight - this.mapWidgetHeight;

        // Zoom directly to target position - but clamp against the region above
        this.scrollPos.copy(this.targetScrollPos);
        this.scrollPos.x = THREE.Math.clamp(this.scrollPos.x, regionMinX, maxScrollX);
        this.scrollPos.y = THREE.Math.clamp(this.scrollPos.y, regionMinY, maxScrollY);
      }

      // update affected widgets
      this.updatePlayerWidget();
      this.applyScrolling();
    }

    // compute min zoomScale so that we stop zoom-out when whole mapImage fits into the widget
  }, { key: "getMinZoomLevel", value: function getMinZoomLevel() {
      var minScaleX = this.mapWidgetWidth / this.mapImageWidth;
      var minScaleY = this.mapWidgetHeight / this.mapImageHeight;
      return Math.log2(Math.min(minScaleX, minScaleY));
    }

    // animate zoom-scale to smoothly follow current targetZoomLevel
  }, { key: "updateZoomScale", value: function updateZoomScale(elapsed) {

      var delta = this.targetZoomLevel - this.zoomLevel;

      // remember zoom-direction
      var zoomOut = delta > 0;

      // Temporarily drop sign, so that we can assume positive values for smoothing
      delta = Math.abs(delta);

      // apply smoothing
      delta = motionSmoothing(delta, elapsed, this.zoomSpeed, this.lastZoomSpeed, this.zoomAcc);

      if (elapsed) {
        this.lastZoomSpeed = delta / elapsed;
      }

      // update zoomLevel and zoomScale accordingly
      this.zoomLevel += delta * (zoomOut ? 1 : -1);
      this.setZoomScale(Math.pow(2, this.zoomLevel));
    } }, { key: "setWidgetSize", value: function setWidgetSize(

    w, h) {
      this.mapWidgetWidth = w;
      this.mapWidgetHeight = h;

      var wStr = toPixels(w);
      var hStr = toPixels(h);
      this.placeholderDiv.style.width = wStr;
      this.placeholderDiv.style.height = hStr;
      this.mapWidget.style.width = wStr;
      this.mapWidget.style.height = hStr;
      this.update();
    }

    // Update mapWidget size based on canvas size
  }, { key: "updateMapSize", value: function updateMapSize() {
      var canvasWidth = this.viewer.container.clientWidth;
      var canvasHeight = this.viewer.container.clientHeight;

      var longEdge = Math.max(canvasWidth, canvasHeight);
      var shortEdge = Math.min(canvasWidth, canvasHeight);

      // Restrict mapSize to not exceed a certain percentage of canvas width/height
      var mapSize = Math.min(this.relMapWidgetSizeLongEdge * longEdge, this.relMapWidgetSizeShortEdge * shortEdge);
      this.setWidgetSize(mapSize, mapSize);
    }

    // Relocate BimWalk info button to avoid overlap with Map widget
  }, { key: "updateBimWalkInfoButtonPos", value: function updateBimWalkInfoButtonPos() {
      var bimWalk = this.viewer.getExtension(BIMWALK_EXT);
      var button = bimWalk && bimWalk.getInfoButton();
      if (!button) {
        return;
      }

      // Only reserve space minimap is visible or about to fade in.
      var style = window.getComputedStyle(this.mapWidget);
      var visible = this.visible || style.opacity > 0;
      var reservedWidth = visible ? this.mapWidgetWidth : 0;

      // Includes space between InfoButton and MapWidget + Space between MapWidget and right canvas boundary
      var Margin = 20;
      var right = reservedWidth + Margin;
      button.style.right = toPixels(right);
    } }, { key: "isOutside", value: function isOutside()

    {
      return !this.mapPixelValid(this.playerPos.x, this.playerPos.y);
    } }, { key: "mapPixelValid", value: function mapPixelValid(

    x, y) {
      return x >= 0 && y >= 0 && x < this.mapImageWidth && y < this.mapImageHeight;
    } }]);return Minimap3DExtension;}(av.Extension);


namespace.Minimap3DExtension = Minimap3DExtension;

Autodesk.Viewing.theExtensionManager.registerExtension(myExtensionName, Minimap3DExtension);

/***/ }),

/***/ "./extensions/AEC/Minimap3D/MinimapTool.js":
/*!*************************************************!*\
  !*** ./extensions/AEC/Minimap3D/MinimapTool.js ***!
  \*************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return MinimapTool; });
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}

var zAxis = new THREE.Vector3(0, 0, 1);


// Implements interaction to move player position and view direction in the Minimap
var MinimapTool = /*#__PURE__*/function () {
  function MinimapTool(parent) {var trackUsage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;_classCallCheck(this, MinimapTool);
    this.parent = parent;

    this.trackUsage = trackUsage;
    this.avatarInteractionTracked = false;
    this.zoomTracked = false;

    this.dragDirectionStart = this.dragDirectionStart.bind(this);
    this.dragDirectionMove = this.dragDirectionMove.bind(this);
    this.dragDirectionEnd = this.dragDirectionEnd.bind(this);

    this.dragPositionStart = this.dragPositionStart.bind(this);
    this.dragPositionMove = this.dragPositionMove.bind(this);
    this.dragPositionEnd = this.dragPositionEnd.bind(this);

    this.onWheel = this.onWheel.bind(this);
    this.onDblClick = this.onDblClick.bind(this);

    // when dragging view direction, we lastAngle stores the angle between +y and the line from playerPos to last mouse position.
    this.lastAngle = undefined;

    // Zoom-factor change per mouse-wheel delta
    this.zoomSensitivity = 0.1;
  }_createClass(MinimapTool, [{ key: "onWheel", value: function onWheel(

    e) {

      // If the avatar is outside the map, we don't know where to zoom-to and show the whole map.
      // Possible improvements: Add panning and use current mouse-position as focus.
      if (this.parent.isOutside()) {
        return;
      }

      // TODO: Use ToolController or consider annoying browser differences
      var delta = e.wheelDelta / 40;

      // modify zoomScale
      var zoomLevelNew = this.parent.targetZoomLevel + delta * this.zoomSensitivity;

      // zoomLevel of 0 corresponds to zoomScale 2^0 = 1 => maximum available map resolution.
      var zoomLevelMax = 0;

      // clamp against valid zoom range
      var zoomLevelMin = this.parent.getMinZoomLevel();
      zoomLevelNew = THREE.Math.clamp(zoomLevelNew, zoomLevelMin, zoomLevelMax);

      this.parent.targetZoomLevel = zoomLevelNew;

      if (!this.zoomTracked) {
        this.zoomTracked = true;
        this.trackUsage && this.trackUsage({
          zoom_tracked: true });

      }
    } }, { key: "activate", value: function activate()

    {
      this.parent.playerPositionWidget.posCircle.addEventListener('mousedown', this.dragPositionStart);
      this.parent.playerPositionWidget.addEventListener('mousedown', this.dragDirectionStart);
      this.parent.mapWidget.addEventListener('wheel', this.onWheel);
      this.parent.mapWidget.addEventListener('dblclick', this.onDblClick);
    } }, { key: "deactivate", value: function deactivate()

    {
      // TODO:
      //   Unify 'dragDirectionMove() / dragDirectionEnd()' listeners handling
      this.dragDirectionEnd();

      this.parent.playerPositionWidget.posCircle.removeEventListener('mousedown', this.dragPositionStart);
      this.parent.playerPositionWidget.removeEventListener('mousedown', this.dragDirectionStart);
      this.parent.mapWidget.removeEventLister('dblclick', this.onDblClick);
    }

    // Convert event client coords to absolute (=zoom and scroll-independent) pixel-coords on the map.
  }, { key: "getMapPosition", value: function getMapPosition(e) {
      // get minimap pixel coords
      var clientRect = this.parent.mapWidget.getBoundingClientRect();
      var x = e.clientX - clientRect.x;
      var y = e.clientY - clientRect.y;

      // apply scroll-position offset
      x += this.parent.scrollPos.x;
      y += this.parent.scrollPos.y;

      // apply zoom-scale, so that result is in full-resolution map pixels
      x /= this.parent.zoomScale;
      y /= this.parent.zoomScale;

      return { x: x, y: y };
    } }, { key: "dragPositionStart", value: function dragPositionStart(

    e) {
      window.addEventListener('mousemove', this.dragPositionMove);
      window.addEventListener('mouseup', this.dragPositionEnd);

      // Make sure that map doesn't scroll/follow while we are moving the avatar
      this.parent.autoScrollLocked = true;

      e.stopPropagation();
    } }, { key: "dragPositionMove", value: function dragPositionMove(

    e) {
      // get minimap pixel coords
      var _this$getMapPosition = this.getMapPosition(e),x = _this$getMapPosition.x,y = _this$getMapPosition.y;

      // clamp x/y to map extent => avoid dragging out of the map
      x = THREE.Math.clamp(x, 0, this.parent.mapImageWidth);
      y = THREE.Math.clamp(y, 0, this.parent.mapImageHeight);

      var camera = this.parent.viewer.impl.camera;

      // keep z the same as before
      var zWorld = camera.position.z;

      // save current pos
      var oldPosition = camera.position.clone();

      var pos3D = this.parent.mapPixelsToWorld(x, y, zWorld);

      // move camera to new 3D position
      camera.position.copy(pos3D);

      // apply delta to the target vector
      var delta = camera.position.clone().sub(oldPosition);

      camera.target.add(delta);
      camera.target.z = zWorld;

      this.parent.viewer.impl.invalidate(true, true);
      this.parent.onCameraMoved();

      e.stopPropagation();
    } }, { key: "dragPositionEnd", value: function dragPositionEnd(

    e) {
      this.parent.autoScrollLocked = false;

      window.removeEventListener('mousemove', this.dragPositionMove);
      window.removeEventListener('mouseup', this.dragPositionEnd);
      e.stopPropagation();

      if (!this.avatarInteractionTracked) {
        this.avatarInteractionTracked = true;
        this.trackUsage && this.trackUsage({
          avatar_interaction_tracked: true });

      }
    } }, { key: "dragDirectionStart", value: function dragDirectionStart(

    e) {
      // remember angle between north and (playerPos, mousePos) at dragStart
      var p1 = this.parent.playerPos;
      var p2 = this.getMapPosition(e);
      this.lastAngle = this.parent.computeAngle(p1, p2);

      window.addEventListener('mousemove', this.dragDirectionMove);
      window.addEventListener('mouseup', this.dragDirectionEnd);
    } }, { key: "dragDirectionMove", value: function dragDirectionMove(

    e) {
      // compute current angle
      var p1 = this.parent.playerPos;
      var p2 = this.getMapPosition(e);
      var newAngle = this.parent.computeAngle(p1, p2);
      var delta = this.lastAngle - newAngle;

      // apply delta to view direction
      var camera = this.parent.viewer.impl.camera;
      var viewVec = camera.target.clone().sub(camera.position);
      viewVec.applyAxisAngle(zAxis, THREE.Math.degToRad(delta));
      viewVec.add(camera.position);
      camera.target.copy(viewVec);

      this.parent.viewer.impl.setViewFromCamera(camera, true);
      this.parent.onCameraMoved();

      this.lastAngle = newAngle;
    } }, { key: "dragDirectionEnd", value: function dragDirectionEnd()

    {
      window.removeEventListener('mousemove', this.dragDirectionMove);
      window.removeEventListener('mouseup', this.dragDirectionEnd);
    } }, { key: "onDblClick", value: function onDblClick(

    e) {
      // get minimap pixel coords
      var _this$getMapPosition2 = this.getMapPosition(e),x = _this$getMapPosition2.x,y = _this$getMapPosition2.y;
      if (!this.parent.mapValid || !this.parent.mapPixelValid(x, y)) {
        return;
      }

      // preserve camera-direction
      var camera = this.parent.viewer.impl.camera;
      var dir = camera.getWorldDirection();

      // when coming from an overview perspective, we don't want to just see the ground afterwards
      dir.z = Math.max(dir.z, 0.0);

      // choose z based on current level
      var level = this.parent.getCurrentLevel();
      var model = this.parent.mapModels && this.parent.mapModels[0];
      if (!level || !model) {
        return;
      }

      // determine avatar height - considering model unit scale (visible models must always have compatible units)
      // TODO: We should unify avatar height code in PlaceMe, Minimap, and BimWalk
      var avatarHeight = 1.7 / model.getUnitScale(); // 1.7m
      var zWorld = level.zMin + avatarHeight;

      // Should usually not happen unless level data is weird for some reason
      if (!isFinite(zWorld)) {
        return;
      }

      // Compute new camera position
      var pos3D = this.parent.mapPixelsToWorld(x, y, zWorld);
      var target = pos3D.clone().add(dir);
      var dstView = {
        position: pos3D,
        target: target,
        up: camera.up };


      var wasOutside = this.parent.isOutside();
      if (wasOutside) {
        // Immediately move to target position. When coming from outside (e.g. overview perspective),
        // a transition would need to fly very fast and potentially through several walls.
        // So, it would need some extra work to make it look good. Since the minimap already gives
        // a clue on where you are, we just jump there directly for this case.
        camera.position.copy(pos3D);
        camera.target.copy(pos3D).add(dir);
        this.parent.viewer.impl.invalidate(true, true);
        this.parent.onCameraMoved();

        // zoom-in map to target position
        this.parent.targetZoomLevel = 0;
      } else {
        // Use flight transition to new position
        Autodesk.Viewing.Private.flyToView(this.parent.viewer, dstView, 1.0);
      }

      e.stopPropagation();
    } }]);return MinimapTool;}();

/***/ }),

/***/ "./extensions/AEC/hyperlinks/HyperlinkExtension.js":
/*!*********************************************************!*\
  !*** ./extensions/AEC/hyperlinks/HyperlinkExtension.js ***!
  \*********************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return HyperlinkExtension; });
/* harmony import */ var _HyperlinkTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./HyperlinkTracker */ "./extensions/AEC/hyperlinks/HyperlinkTracker.js");
function _typeof(obj) {if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {_typeof = function _typeof(obj) {return typeof obj;};} else {_typeof = function _typeof(obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};}return _typeof(obj);}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}function _possibleConstructorReturn(self, call) {if (call && (_typeof(call) === "object" || typeof call === "function")) {return call;}return _assertThisInitialized(self);}function _assertThisInitialized(self) {if (self === void 0) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}function _getPrototypeOf(o) {_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {return o.__proto__ || Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function");}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } });if (superClass) _setPrototypeOf(subClass, superClass);}function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);}

var av = Autodesk.Viewing;
var namespace = AutodeskNamespace('Autodesk.AEC');
var myExtensionName = 'Autodesk.AEC.HyperlinkExtension';


// Hyperlink extension which will display hyperlinks in 2D sheets to other sheets
//  @param {Number} options.rootBubbleNode Root bubble node of model
//  @callback options.loadViewableCb Will be called in case a hyperlink is clicked with bubble node of the sheet and
//      the total number of hyperlinks present in the sheet
//  @callback options.hyperlinksAddedCb Will be called each time hyperlinks have been added to a sheet with the id of
//      the model and the total number of hyperlinks present in the sheet
var HyperlinkExtension = /*#__PURE__*/function (_av$Extension) {_inherits(HyperlinkExtension, _av$Extension);
  function HyperlinkExtension(viewer, options) {var _this;_classCallCheck(this, HyperlinkExtension);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(HyperlinkExtension).call(this, viewer, options));

    _this.hyperlinkTracker = new _HyperlinkTracker__WEBPACK_IMPORTED_MODULE_0__["default"](_this.viewer, _this.options.rootBubbleNode,
    _this.options.loadViewableCb, _this.options.hyperlinksAddedCb);return _this;
  }_createClass(HyperlinkExtension, [{ key: "load", value: function load()

    {
      this.viewer.toolController.activateTool('hyperlink-tracker');
      return true;
    } }, { key: "unload", value: function unload()

    {
      this.viewer.toolController.deactivateTool('hyperlink-tracker');
      return true;
    } }]);return HyperlinkExtension;}(av.Extension);


namespace.HyperlinkExtension = HyperlinkExtension;
Autodesk.Viewing.theExtensionManager.registerExtension(myExtensionName, HyperlinkExtension);

/***/ }),

/***/ "./extensions/AEC/hyperlinks/HyperlinkTracker.js":
/*!*******************************************************!*\
  !*** ./extensions/AEC/hyperlinks/HyperlinkTracker.js ***!
  \*******************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return HyperlinkTracker; });

//A tool that:
//Implements heuristically derived hyperlinks from text geometries in F2D drawings (and mouse hover support for hyperlinks)
//Taken from Fluent POC:
// https://git.autodesk.com/fluent/lmv-ui/blob/master/app/scripts/tools/mouse-tracker.js#L273
// https://git.autodesk.com/fluent/lmv-ui/blob/master/app/scripts/tools/mouse-tracker.js#L171




var av = Autodesk.Viewing,
avp = Autodesk.Viewing.Private;

function HyperlinkTracker(viewer, rootBubbleNode, loadViewableCb, hyperlinksAddedCb) {
  av.ToolInterface.call(this);
  this.names = ['hyperlink-tracker'];
  viewer.toolController.registerTool(this);

  var _viewer = viewer;
  var _loadViewableCb = loadViewableCb;
  var _hyperlinksAddedCb = hyperlinksAddedCb;
  var _idRead = [0, 0];
  var _linkMaps = {};
  var _dbId = 0;
  var _lastX, _lastY;
  var _mouseMoved = false;
  var _isDragging = false;

  this.update = function () {
    if (!_isDragging) {
      if (_mouseMoved) {
        var vp = _viewer.impl.clientToViewport(_lastX, _lastY);
        _dbId = _viewer.impl.renderer().idAtPixel(vp.x, vp.y, _idRead);
        _mouseMoved = false;
      }
    } else {
      _dbId = 0;
    }
    return false;
  };

  function getCurrentModel() {
    var mq = _viewer.impl.modelQueue();
    var visibleModels = mq.getModels();

    return visibleModels.length === 1 ? visibleModels[0] : undefined;
  }

  function getCurrentLinkMap() {
    var linkMap = _linkMaps[_idRead[1]];

    //Fallback for when a single model is loaded and the Model ID buffer is not working
    if (!linkMap) {
      var cm = getCurrentModel();
      if (cm) {
        linkMap = _linkMaps[cm.id];
      }
    }

    return linkMap;
  }

  function isLinkMapValid(map) {
    return map && Object.keys(map).length > 0;
  }

  this.handleSingleClick = function () {
    if (!_viewer.model || !_viewer.model.is2d())
    return;

    var vp = _viewer.impl.clientToViewport(_lastX, _lastY);
    _dbId = _viewer.impl.renderer().idAtPixel(vp.x, vp.y, _idRead);

    var linkMap = getCurrentLinkMap();

    var linkNode = isLinkMapValid(linkMap) ? linkMap[_dbId] : null;

    if (linkNode) {
      _loadViewableCb(linkNode, linkMap.numHyperlinks);
      return true;
    }

    return false;
  };

  this.handleButtonDown = function (event) {
    _isDragging = true;
    _lastX = event.canvasX;
    _lastY = event.canvasY;
    return false;
  };

  this.handleButtonUp = function () {
    _isDragging = false;
    return false;
  };

  this.handleMouseMove = function (event) {
    _lastX = event.canvasX;
    _lastY = event.canvasY;
    _mouseMoved = true;
    return false;
  };

  function addRenderBox(vbb, f2d, stringIndex, modelScale) {
    var i4 = 4 * stringIndex;

    var miny = f2d.stringBoxes[i4 + 1];
    var maxy = f2d.stringBoxes[i4 + 3];
    var border = (maxy - miny) * 0.2;
    miny = miny - border;
    maxy = maxy + border;
    var minx = f2d.stringBoxes[i4] - border;
    var maxx = f2d.stringBoxes[i4 + 2] + border;

    var dbId = f2d.stringDbIds[stringIndex];
    var vbase = vbb.vcount;

    var linkFillColor = 0x77bfbb3f;
    vbb.addVertexPolytriangle(minx, miny, linkFillColor, dbId, 0, 0);
    vbb.addVertexPolytriangle(maxx, miny, linkFillColor, dbId, 0, 0);
    vbb.addVertexPolytriangle(maxx, maxy, linkFillColor, dbId, 0, 0);
    vbb.addVertexPolytriangle(minx, maxy, linkFillColor, dbId, 0, 0);

    vbb.addIndices([0, 1, 2, 0, 2, 3], vbase);

    vbb.addSegment(minx, miny, maxx, miny, 0, -2 * modelScale, linkFillColor | 0xff000000, dbId, 0, 0, 0);
    vbb.addSegment(maxx, miny, maxx, maxy, 0, -2 * modelScale, linkFillColor | 0xff000000, dbId, 0, 0, 0);
    vbb.addSegment(maxx, maxy, minx, maxy, 0, -2 * modelScale, linkFillColor | 0xff000000, dbId, 0, 0, 0);
    vbb.addSegment(minx, maxy, minx, miny, 0, -2 * modelScale, linkFillColor | 0xff000000, dbId, 0, 0, 0);
  }

  function addLinkBoxMesh(model, vbb) {
    var fragId = model.getFragmentList().vizmeshes.length;
    var mdata = { mesh: vbb.toMesh(), is2d: true, packId: '0', meshIndex: fragId };
    avp.BufferGeometryUtils.meshToGeometry(mdata);

    var matman = _viewer.impl.matman();
    var materialId = matman.create2DMaterial(model, {});
    var m = _viewer.impl.setupMesh(model, mdata.geometry, materialId, model.getData().loadOptions.placementTransform);
    model.activateFragment(fragId, m);
    return fragId;
  }

  function removeLinkBoxMesh(model, fragId) {
    // get link box mesh
    var fragList = model.getFragmentList();
    var mesh = fragList.vizmeshes[fragId];

    // Dispose geometry. MaterialManager will take care of the material dispose on model unload. 
    // We don't dispose material here because it may be shared with other fragments of the model.
    mesh.geometry.dispose();

    delete fragList.vizmeshes[fragId];
  }

  function initializeHyperlinks(model) {
    if (!model || !model.is2d()) {
      return;
    }

    // Check if this model has been initialized already
    var linkMap = _linkMaps[model.id];
    if (linkMap) {
      return;
    }
    linkMap = _linkMaps[model.id] = {};

    // find all sheets of the same document
    var node = model.getDocumentNode();
    var root = node && node.getRootNode();
    var sheets = root && root.search({ role: '2d', type: 'geometry' });
    if (!sheets || !sheets.length) {
      return;
    }

    var currentSheetBasePath = '';
    if (model.myData) {
      currentSheetBasePath = model.myData.basePath;
    }

    var getSheetUrn = function getSheetUrn(sheet) {
      var resourceType = 'resource';
      if (sheet.children) {var _iteratorNormalCompletion = true;var _didIteratorError = false;var _iteratorError = undefined;try {
          for (var _iterator = sheet.children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {var child = _step.value;
            if (child.type() === resourceType) {
              var urn = child.urn();
              if (urn) {
                // We remove the primaryGraphics.f2d part from the urn
                var elements = urn.split('/');
                elements.pop();
                return elements.join('/');
              }
            }
          }} catch (err) {_didIteratorError = true;_iteratorError = err;} finally {try {if (!_iteratorNormalCompletion && _iterator.return != null) {_iterator.return();}} finally {if (_didIteratorError) {throw _iteratorError;}}}
      }
      return null;
    };

    var sheetIds = sheets.map(function (s) {
      var sheetUrn = getSheetUrn(s);
      //exclude current sheet, i. e. no links to self
      if (currentSheetBasePath.indexOf(sheetUrn) === -1) {
        var split = s.name().split(' ');
        var sheetName = split[0];
        if (sheetName.length > 2) {
          return sheetName;
        }
      }
      return '';
    });

    //while finding hyperlink strings, we will also
    //create a geometry buffer containing all their bboxes
    //so we can render with their IDs.
    linkMap.numHyperlinks = 0;
    var vbb = new avp.VertexBufferBuilder();
    var modelScale = 1.0 / (model.getData().loadOptions.modelScale || 1);
    var f2d = model.getData();
    for (var i = 0; i < f2d.strings.length; i++) {

      var idx = sheetIds.indexOf(f2d.strings[i]);

      if (idx >= 0) {
        linkMap[f2d.stringDbIds[i]] = sheets[idx];

        addRenderBox(vbb, f2d, i, modelScale);
        linkMap.numHyperlinks++;
      }
    }

    linkMap.boxFragId = addLinkBoxMesh(model, vbb);

    if (_hyperlinksAddedCb) {
      _hyperlinksAddedCb(e.model.id, linkMap.numHyperlinks);
    }
  }

  function onGeomLoaded(e) {
    initializeHyperlinks(e.model);
  }

  // Execute cb for all sheets that are (completely) in memory
  function forAllSheetsInMemory(cb) {
    var allModels = _viewer.getVisibleModels().concat(_viewer.getHiddenModels());
    for (var i = 0; i < allModels.length; i++) {
      var model = allModels[i];
      if (model.is2d() && model.isLoadDone()) {
        cb(model);
      }
    }
  }

  function removeHyperlinks() {

    // Keep _linkMaps consistent with models: We don't want to leak dead box meshes in the models.
    // Therefore, we remove them from all models in memory
    forAllSheetsInMemory(function (model) {
      var linkMap = _linkMaps[model.id];
      if (linkMap) {
        removeLinkBoxMesh(model, linkMap.boxFragId);
      }
    });

    _linkMaps = {};

    // make sure that removed hyperlink quads are not visible anymore
    _viewer.impl.invalidate(true, true);
  }

  this.activate = function () {

    // Make sure that we don't forget to init hyperlinks if the geom-load event has already happened
    forAllSheetsInMemory(function (model) {
      initializeHyperlinks(model);
    });

    _viewer.addEventListener(av.GEOMETRY_LOADED_EVENT, onGeomLoaded);

    // make sure that added hyperlink quads appear instantly
    _viewer.impl.invalidate(true, true);
  };

  this.deactivate = function () {
    _viewer.removeEventListener(av.GEOMETRY_LOADED_EVENT, onGeomLoaded);
    removeHyperlinks();
  };

  // Show a hand cursor, if the cursor is close to a hyperlink
  this.getCursor = function () {
    var linkMap = getCurrentLinkMap();

    if (_dbId < -1 && isLinkMapValid(linkMap) && linkMap[_dbId]) {
      return 'pointer';
    }

    return null;
  };
}

var namespace = AutodeskNamespace('Autodesk.AEC');
namespace.HyperlinkTracker = HyperlinkTracker;

/***/ }),

/***/ "./extensions/AEC/levels/FloorSelector.js":
/*!************************************************!*\
  !*** ./extensions/AEC/levels/FloorSelector.js ***!
  \************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return FloorSelector; });
/* harmony import */ var _FloorSelectorFilter_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./FloorSelectorFilter.js */ "./extensions/AEC/levels/FloorSelectorFilter.js");
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}

var av = Autodesk.Viewing;
var avp = Autodesk.Viewing.Private;
var namespace = AutodeskNamespace('Autodesk.AEC');


// FloorSelector provides graphics effects to be used by UI for floor selection.
//
// This includes:
//
//  - Setting cutplanes accordingly when a floor is selected.
//
//  - Animated transitions if the selected floor changes.
//
//  - Applying mouse-over highlighting of floors - to be used when hovering over a floor button
//
//  - "Ghost-Floors": By default, we render selected floors only. If the mouse enters the floor panel, we
//     also fade-in the other floors, but with strongly reduced opacity. (+ fade-out on mouse leave)
//
//
// How to use it:
//
//  1. Create a FloorSelector by passing the viewer to the ctor.
//
//  2. Before using the FloorSelector, you have to provide floor data that you get from the Revit metadata
//     json file. (see setFloorData comment)
//
//  3. Connect events for hovering over floor selector UI panel:
//     - Connect mouseover  to floorSelector.enterHoverMode()
//     - Connect mouseleave to floorSelector.existHoverMode()
//
//  4. Connect events for hovering over floor selection buttons: For each floor button...
//     - Connect mouseover  to floorSelector.rollOverFloor(floorIndex) - floorIndex must be the index into the floor array (see setFloorData)
//     - Connect mouseleave to floorSelector.rollOverFloor()
//
//  5. Connect floor selection button: For each floor button,
//     connect button mousedown to floorSelector.selectFloor(floorIndex, true)
//
//  6. If the set of visible models has changed
//
//  7. When discarding the FloorSelector (while keeping the Viewer alive), call FloorSelector dtor.
//
// How to enable the optional filtering of objects by dbIds per model provided by the AECModelData.json on level selection?
//
//  1. You have to provide floor filter data containing a Map of dbIds per model. The key has to be the model version URN (see setFloorFilterData).
//
//     Example on how to set the floor filter data:
//
//     const modelsDbIds = new Map();
//     modelsDbIds.set(model, [1, 2, 3, 4]);
//     var floorFilterData = {
//         modelsDbIds: modelsDbIds
//     };
//
//     floorSelector.setFloorFilterData(floorFilterData);
//
// How to control the calculated lower level boundary value by defining the levelHeightFactor factor? The factor is multiplied with the level height
// and added to the level minZ value. This newly calculated minZ value defines the lower level boundary used to filter the Floor and Ceiling elements.
//
//     Example on how to set the floor filter data with a levelHeightFactor:
//
//     const modelsDbIds = new Map();
//     modelsDbIds.set(model, [1, 2, 3, 4]);
//     var floorFilterData = {
//         modelsDbIds: modelsDbIds,
//         levelHeightFactor: 0.6 // Allowed values have to be within 0-1.
//     };
//
//     floorSelector.setFloorFilterData(floorFilterData);
//
// Technical requirements/restrictions to be aware of:
//
//  - Cross-Fading Support: FloorSelector uses LMV render target fading for some effects. For this, it activates
//    cross-fading support in LMV (if not active already). This requires 2 extra color targets, i.e.
//    consumes some additional GPU-side memory.
//
//  - Camera Movement: The camera should not be moving while using the floor selector.
//    This is because we partially use static images for the fading effects.
//    If the user moves the camera, we instantly switch off the ghost floors.
//
//  - SAO opacity: FloorSelector needs to temporarily hide SAO. For this, we have to overwrite SAO opacity
//    and recover it later. This requires that the SAO opacity is not changed in the meantime
//    while using the FloorSelector. Otherwise, it will cause a warning and may cause visual
//    artifacts.



// Time in seconds to fade in/out ghosted floors when hovering over the floor selector panel
var GhostFloorFadingTime = 0.5;

// Opacity for ghost floors when fade-in is finished.
var MaxGhostFloorOpacity = 0.2;

// These should actually be infinity and -infinity, but since the values are passed to a shader,
// we have to use large finite values instead. Setting as cutplane elevations actually corresponds to
// switching cutplanes off. But, changes the number of cutplanes triggers expesnive shader recompiles.
var MaxZLimit = 1e20;
var MinZLimit = -MaxZLimit;

// Internally used enum values for state management
var FloorRenderMode = {

  // mouse is hovering over a floor button
  Hovering: 0,

  // new floor has been selected and anim is running
  Transition: 1,

  // default rendering
  Off: 2 };


// Reserved floor-index constant to select all floors at once.
var AllFloors = -1;
var NoFloor = undefined;

// Used for setCutPlane calls to lmv. This ensures that FloorSelector controls its own cutplanes,
// which is independent of other cutplane changes like from SectionTool.
var CutPlaneSetName = 'Autodesk.AEC.FloorSelector';var

FloorSelector = /*#__PURE__*/function () {

  // @param {Viewer3D} viewer
  function FloorSelector(viewer) {_classCallCheck(this, FloorSelector);

    av.EventDispatcher.prototype.apply(this);

    this._viewer = viewer;
    this._renderer = viewer.impl.renderer();

    // Make sure that ghost-floors are switched off as soon as the user starts navigating.
    // This is needed because the selected floor is just a static image when ghost-floors are shown.
    this._cameraMovedCB = this._interruptFading.bind(this);
    viewer.addEventListener(av.CAMERA_CHANGE_EVENT, this._cameraMovedCB);

    // Stop panel-hover effect on viewer-resize: Ghost-floors use a static image overlay that becomes unusable
    // if the target size changes.
    this._viewerResizeCB = this._onViewerResized.bind(this);
    viewer.addEventListener(av.VIEWER_RESIZE_EVENT, this._viewerResizeCB);

    // If SAO is switched off, we have to switch off roll-over highlighting too.
    this._renderOptionsChangedCB = this._onRenderOptionsChanged.bind(this);
    viewer.addEventListener(av.RENDER_OPTION_CHANGED_EVENT, this._renderOptionsChangedCB);

    // callback for the floor selection filtering
    this._floorSelectionFilterToBeUpdated = this._runFloorSelectorFilterEventHandler.bind(this);
    viewer.addEventListener(av.MODEL_ADDED_EVENT, this._floorSelectionFilterToBeUpdated);
    viewer.addEventListener(av.OBJECT_TREE_CREATED_EVENT, this._floorSelectionFilterToBeUpdated);

    // callback for the unloading of disabled models
    this._modelUnloadingCB = this._runModelUnloadingEventHandler.bind(this);
    viewer.addEventListener(av.MODEL_UNLOADED_EVENT, this._modelUnloadingCB);

    // {Object[]} Contains the floor data. see setFloorData() comment.
    this._floors = [];

    // current state (hover/transition/off)
    this._currentMode = FloorRenderMode.Off;
    this._hovering = false; // used to track hovering state while in transition mode

    // current floor section (if cutplanes are active)
    this._floorSectionMin = undefined;
    this._floorSectionMax = undefined;

    // Determine z-range for "all-floors"
    // We determine that dynamically from the currently visible models.
    // Note that we need this value also for cutplane transitions - so we cannot
    // simply choose something arbitrarily far outside.
    this._zMinAllModels = undefined;
    this._zMaxAllModels = undefined;

    // {AnimControl} Needed to interrupt a running cutplane animation (see moveFloors)
    this._floorAnim = null;

    // {AnimControl} Needed to interrupt a runnign fade-in/out anim for ghost-floors
    this._fadeAnim = null;

    // Opacity of the render target that shows floors that are currently not selected ("ghost floors")
    // Always 0.0 if the extra target for ghost floors is not used.
    this._ghostFloorOpacity = 0.0;

    this._currentMode = FloorRenderMode.Off;

    // {number|undefined} index of selected floor (or undefined if no floor is selected)
    this._currentFloor = undefined;

    // We render ghost-floors without AO, because AO cannot be smoothly faded out with them.
    // To activate AO, we need to 'backup' the current AO opacity and recover it later.
    this._aoVisible = true;
    this._aoOpacity = undefined; // if ao is blocked, we store the original ao opacity here to recover it later.

    this._floorSelectorFilter = new _FloorSelectorFilter_js__WEBPACK_IMPORTED_MODULE_0__["default"](this._viewer);
    this._floorFilterData = undefined;

    // Indicates if we are currently using mouse-over highlighting for a floor.
    this._floorRollOverActive = false;

    // If disabled, make sure that cutplanes keep unset. This is needed to avoid side-effects on 2D views.
    this.enabled = true;
  }_createClass(FloorSelector, [{ key: "dtor", value: function dtor()

    {
      if (this._viewer) {
        this._viewer.removeEventListener(av.CAMERA_CHANGE_EVENT, this._cameraMovedCB);
        this._viewer.removeEventListener(av.VIEWER_RESIZE_EVENT, this._viewerResizeCB);
        this._viewer.removeEventListener(av.RENDER_OPTION_CHANGED_EVENT, this._renderOptionsChangedCB);
        this._viewer.removeEventListener(av.OBJECT_TREE_CREATED_EVENT, this._floorSelectionFilterToBeUpdated);
        this._viewer.removeEventListener(av.MODEL_ADDED_EVENT, this._floorSelectionFilterToBeUpdated);
        this._viewer.removeEventListener(av.MODEL_UNLOADED_EVENT, this._modelUnloadingCB);
        this._viewer = null;
      }
    }

    // -----------------
    // --- Main API ----
    // -----------------

    // Before selecting any floors, setFloorData() must be called to provide the elevation ranges
    // of all available floors.
    //  @param {Object[]} floors - data about available floors, each item f must contain two finite floats f.zMin < f.zMax
  }, { key: "resetState",









    // sets back level isolation, selection filter and the floors.
    value: function resetState() {
      // we have to clear the settings
      this._floors = [];
      this._selectFloor(NoFloor);
      this._clearFloorSection();
      this._floorSelectorFilter.clearFilter();
    }

    // Before any objects can be filtered using the FloorSelectorFilter, setFloorFilterData() must be called to
    // provide the array of Floor and Ceiling dbIds per model.
    //  @param {Object[]} floorFilterData - A floor filter data object containing an array of dbIds per model.
  }, { key: "enterHoverMode",







    // Fades in the ghost-floors.
    // Triggered when floor selection begins, i.e., mouse is entering floor selector panel.
    value: function enterHoverMode() {

      // make sure that the ghosted floors are in a static image,
      // so that we can move the solid floor
      if (this._currentMode !== FloorRenderMode.Transition) {
        this._setMode(FloorRenderMode.Hovering);
      }

      // track hovering state - so that we can recover it after transitions
      this._hovering = true;
    }

    // Fades out the ghost floors.
    // Triggered when floor selection ends, i.e., mouse is leaving the floor selector panel.
  }, { key: "exitHoverMode", value: function exitHoverMode() {

      // If a floor-transition is running, we only track the hover state and
      // set the mode when the transition has finished.
      if (this._currentMode !== FloorRenderMode.Transition) {
        this._setMode(FloorRenderMode.Off);
      }
      this._hovering = false;

      // make sure that no spatial filter for mouse-over highlight is set anymore, so that we don't
      // have side-effects on subsequent object selection.
      this._setSpatialFilterForRollOver();
    } }, { key: "_getFadeExtension", value: function _getFadeExtension()

    {
      return this._viewer.getExtension('Autodesk.CrossFadeEffects');
    }

    // Ghosted display of inactive floors on panel hover is only supported if CrossFadeEffects extension is loaded
  }, { key: "_ghostFloorsEnabled", value: function _ghostFloorsEnabled() {
      return Boolean(this._getFadeExtension());
    }

    // Select for which floor rollOver highlighting is shown.
    //   @param {number} [floorIndex] must be either
    //                                a) a valid index into this.floors
    //                                b) a reserved constant (FloorSelector.AllFloors or FloorSelector.NoFloor)
  }, { key: "rollOverFloor", value: function rollOverFloor(floorIndex) {

      // If we don't show ghost-floors, roll-over highlighting does not make much sense if only 1 floor is visible anyway.
      // It just looks confusing, because occasionally it would only be visible for the selected floor and some parts of others
      // that overlap the z-range a bit.
      var enabled = this._ghostFloorsEnabled() || this._currentFloor === NoFloor;

      // rollOver highlight is only possible if SAO is enabled and supported.
      var supported = this._renderer.spatialFilterForRollOverSupported();
      if (floorIndex === undefined || !supported || !enabled) {

        // switch off floor highlight
        this._setSpatialFilterForRollOver();
        this._rollOverHighlightOff();
        return;
      }

      // Activate roll-over highlighting for all objects
      this._rollOverHighlightAll();

      // restrict highlighting to floor range unless all floors are selected.
      this._setSpatialFilterForRollOver(floorIndex);

      // TODO: Clarify why this call is needed. It should actually not required to re-render here.
      this._viewer.impl.invalidate(false, true, true);
    }

    // Sets the currently visible floor.
    //  @param {number}   [floorIndex]    A valid index into the floor data array (see setFloors) selects a single floor.
    //                                    FloorSelector.NoFloor discards the floor selection => all floors visible.
    //  @param {bool}     [useTransition] If true, a short animation is used to morph between previous and new floor
    //  returns false in case no selection cannot be performed
  }, { key: "selectFloor", value: function selectFloor(floorIndex, useTransition) {

      if (!this.floorSelectionValid(floorIndex)) {
        return;
      }

      if (useTransition) {
        this._moveToFloor(floorIndex);
      } else {
        this._selectFloor(floorIndex);
      }

      this._runFloorSelectorFilter();

      // If no ghosting is used, we disable rollOver highlighting if only a single floor is visible.
      if (!this._ghostFloorsEnabled()) {
        this.rollOverFloor();
      }

      this.fireEvent({ type: FloorSelector.CURRENT_FLOOR_CHANGED, levelIndex: floorIndex });
    }

    // Gets the index of the current selected floor or FloorSelector.NoFloor
  }, { key: "floorSelectionValid",



    // Returns whether a floorSelection can be performed with the specified floor
    // checks for valid value, whether floorData is available, the floor is already selected
    // and whether the floor is within the expected range.
    value: function floorSelectionValid() {var newFloor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : NoFloor;
      // force boolean
      return !!((Number.isInteger(newFloor) || newFloor === NoFloor) && // not a valid value
      this.floorData && this.floorData.length !== 0 // has no floor data
      && this.currentFloor !== newFloor // newFloor floor is not selected
      && (newFloor === NoFloor ||
      newFloor >= 0 || this.floorData.length > newFloor)); // new floor is in range;
    }

    // returns true if a dbId is either hidden by FloorSelectorFilter or fully outside the cutplanes
  }, { key: "isVisible", value: function isVisible(model, dbId) {

      // reused tmp variable
      if (!this._tmpNodeBox) {
        this._tmpNodeBox = new Float32Array(6);
      }

      // Determine zMin/zMax to ceck against. We could use _floorSectionMin/Max. But this would
      // make this function depending on current animation state. Since we don't want to do permanent
      // filter-updates during animations, we use currentFloor instead, which represents the target state - independent of animations.
      var floor = this._floors[this._currentFloor];
      if (floor === NoFloor) {
        // No floor selected => Nothing hidden
        return true;
      }

      var instanceTree = model.getInstanceTree();
      if (!instanceTree) {
        // If there is not instance tree, FloorSelectorFilter would have warned already if a floor was selected.
        return true;
      }

      // get zMin/zMax for this node
      var nodeBox = this._tmpNodeBox;
      instanceTree.getNodeBox(dbId, nodeBox);
      var nodeBoxZMin = nodeBox[2];
      var nodeBoxZMax = nodeBox[5];

      // Node is hidden if...
      //  a) outside the level's cutplanes, or
      //  b) hidden by levels filter
      var outsideCutplane = nodeBoxZMin > floor.zMax || nodeBoxZMax < floor.zMin;
      return !outsideCutplane && this._floorSelectorFilter.isVisible(model, dbId);
    } }, { key: "setEnabled", value: function setEnabled(

    enabled) {
      this.enabled = enabled;
      this._applySelectedFloorSection();
    }

    // ------------------------
    // --- Internal methods ---
    // ------------------------
  }, { key: "_stopFloorAnim", value: function _stopFloorAnim()
    {
      if (this._floorAnim) {
        this._floorAnim.stop();
        this._floorAnim = null;
      }
    } }, { key: "_stopFadeAnim", value: function _stopFadeAnim()

    {
      if (this._fadeAnim) {
        this._fadeAnim.stop();
        this._fadeAnim = null;
      }
    } }, { key: "_leaveHoverMode", value: function _leaveHoverMode()

    {

      var fadeExt = this._getFadeExtension();
      if (!fadeExt) {
        // Nothing todo if ghosting effect is not used.
        return;
      }

      // release any baked images
      fadeExt.releaseFadingImage(0);
      fadeExt.releaseFadingImage(1);

      // make sure that model is rendered into default color target
      fadeExt.setModelTargetIndexForAll(undefined);

      // apply cutplanes according to currently selected floor
      this._applySelectedFloorSection();

      // we are now rendering real floors again,
      // so that we can switch SAO on again.
      this._setAOVisible(true);
    }

    // When rendering ghost-floors, the static part is always a static image.
    // Therefore, we have to skip the fading if the user moves the camera.
  }, { key: "_interruptFading", value: function _interruptFading() {

      // If we just left hover-mode, but the floors did not finish to fade out yet,
      // stop the anim and finish it immediately.
      if (!this._hovering && this._fadeAnim && this._fadeAnim.isRunning) {
        this._stopFadeAnim();
        this._leaveHoverMode();
      }
    } }, { key: "_onViewerResized", value: function _onViewerResized()

    {
      // Stop any image-based hovering effects immedately, because the baked ghost-floor image has incorrect size now.
      this._stopFadeAnim();
      this._leaveHoverMode();

      // Restart hovering effect if mouse is still on the panel. Now using the new render target size.
      if (this._hovering) {
        this.enterHoverMode();
      }
    } }, { key: "_onRenderOptionsChanged", value: function _onRenderOptionsChanged()

    {
      // Make sure that we stop using roll-over-floor highlight if the depth
      // target is not available anymore.
      if (this._floorRollOverActive && !this._renderer.spatialFilterForRollOverSupported()) {
        this.rollOverFloor();
      }
    }

    // Get array of all visible models
  }, { key: "_getVisibleModels", value: function _getVisibleModels() {
      var mq = this._viewer.impl.modelQueue();
      return mq.getModels();
    }

    // Updates min/max limits for cutplane z-level, based on the bboxes of all visible models
  }, { key: "_updateZLimits", value: function _updateZLimits() {
      var models = this._getVisibleModels();

      this._zMinAllModels = MaxZLimit;
      this._zMaxAllModels = MinZLimit;
      for (var i = 0; i < models.length; i++) {
        var model = models[i];
        var box = model.getBoundingBox();

        this._zMinAllModels = Math.min(box.min.z, this._zMinAllModels);
        this._zMaxAllModels = Math.max(box.max.z, this._zMaxAllModels);
      }

      // make sure the range is valid also when no models are available
      if (this._zMinAllModels > this._zMaxAllModels) {
        this._zMinAllModels = MinZLimit;
        this._zMaxAllModels = MaxZLimit;
      }
    } }, { key: "_setAOVisible", value: function _setAOVisible(

    visible) {
      if (visible === this._aoVisible) {
        return;
      }
      this._aoVisible = visible;

      var blendPass = this._renderer.getBlendPass();

      var newOpacity = 0.0;
      if (!visible) {
        // ao switched off => backup original ao opacity
        this._aoOpacity = blendPass.uniforms['aoOpacity'].value;
      } else {

        // Opacity should be 0. Any other value indicates that it has been changed from
        // outside while ao was hidden by floor selector.
        var curOpacity = blendPass.uniforms['aoOpacity'].value;
        if (curOpacity !== 0.0) {
          console.warn('ao opacity should not be changed while FloorSelector is in use.');
        }

        // ao switched on => recover original ao opacity
        newOpacity = this._aoOpacity;
      }

      this._renderer.setAOOptions(this._renderer.getAORadius(), this._renderer.getAOIntensity(), newOpacity);
    }

    // @param {number} val - float in [0,1]
  }, { key: "_setGhostFloorOpactiy", value: function _setGhostFloorOpactiy(val) {

      // ghost-floors are always rendered into extra target 1
      var fadeExt = this._getFadeExtension();
      fadeExt && fadeExt.setCrossFadeOpacity(1, this._ghostFloorOpacity);

      this._ghostFloorOpacity = val;

    }

    // Determine an upper bound for the dbIds of all visible models
  }, { key: "_findMaxDBId", value: function _findMaxDBId() {

      var models = this._getVisibleModels();
      var maxDbId = 1;
      for (var i = 0; i < models.length; i++) {

        // get instance tree of next model
        var model = models[i];
        var instTree = model.getInstanceTree();
        if (!instTree) {
          continue;
        }

        // dbIds are consecutive and 1-based
        var maxModelDbId = instTree.objectCount + 1;
        maxDbId = Math.max(maxModelDbId, maxDbId);
      }
      return maxDbId;
    }

    // Activate roll-over highlighting for all objects of all models.
  }, { key: "_rollOverHighlightAll", value: function _rollOverHighlightAll() {
      this._renderer.rolloverObjectId(1);
    }

    // Stop roll-over highlighting.
  }, { key: "_rollOverHighlightOff", value: function _rollOverHighlightOff() {
      this._renderer.rolloverObjectId(0);
    }

    // Apply/Remove spatial filter that restricts rollOver highlighting to a single floor
    //  @param {number} If floorIndex is a valid index into this.floors, highlighting is restricted to that floor.
    //                  Otherwise, the spatial filter is switched off.
  }, { key: "_setSpatialFilterForRollOver", value: function _setSpatialFilterForRollOver(floorIndex) {

      var filter = undefined;
      var floor = this._floors[floorIndex];

      var createSpatialFilter = function createSpatialFilter(zMin, zMax) {
        // Define filter to restrict rollOver highlighting to floor elevation range
        return 'bool spatialFilter(vec3 worldPos) { return (worldPos.z >= float(' + zMin + ') && worldPos.z <= float(' + zMax + ')); }';
      };

      if (floor) {
        filter = createSpatialFilter(floor.zMin, floor.zMax);
      } else if (floorIndex === FloorSelector.AllFloors) {
        filter = createSpatialFilter(this._zMinAllModels, this._zMaxAllModels);
      }

      this._renderer.setSpatialFilterForRollOver(filter);

      // If spatial filter is defined, make sure that ghost floors are always rendered to depth target.
      // Otherwise, the spatial filter for roll-over highlighting does not work.
      var fadeExt = this._getFadeExtension();
      fadeExt && fadeExt.crossFade.setSaoHeuristicEnabled(!filter);

      this._floorRollOverActive = !!filter;
    } }, { key: "_applyFloorSection", value: function _applyFloorSection(

    zMin, zMax) {

      // Do not allow any cutplane when disabled
      if (!this.enabled) {
        this._viewer.impl.setCutPlaneSet(CutPlaneSetName, planes);
        return;
      }

      // reset the defined z values to the minimum in case the value is not specified
      if (!Number.isFinite(zMin)) {
        zMin = MinZLimit;
      }
      if (!Number.isFinite(zMax)) {
        zMax = MaxZLimit;
      }


      var planes = [new THREE.Vector4(0, 0, -1, zMin), new THREE.Vector4(0, 0, 1, -zMax)];
      this._viewer.impl.setCutPlaneSet(CutPlaneSetName, planes);
    }

    // Set cut plane according to currently selected floor
  }, { key: "_applySelectedFloorSection", value: function _applySelectedFloorSection() {

      // If no floor section is active, set cutplanes to maximum range.
      // Doing this instead of clearing them avoids the repeated shader recompile
      var zMin = this._floorSectionMin !== undefined ? this._floorSectionMin : MinZLimit;
      var zMax = this._floorSectionMax !== undefined ? this._floorSectionMax : MaxZLimit;
      this._applyFloorSection(zMin, zMax);
    } }, { key: "_setFloorSection", value: function _setFloorSection(

    minElev, maxElev) {
      this._floorSectionMin = isNaN(minElev) ? undefined : minElev;
      this._floorSectionMax = isNaN(maxElev) ? undefined : maxElev;
      this._applySelectedFloorSection();
    }

    // Temporarily disable floor section cut planes. This is needed to render ghost floors.
  }, { key: "_clearFloorSection", value: function _clearFloorSection() {
      // Changing the number of cutplanes would cause a shader recompile.
      // To avoid that, we set dummy cutplanes instead.
      this._updateZLimits();
      this._applyFloorSection();
    } }, { key: "_setMode", value: function _setMode(

    mode) {var _this = this;

      if (mode === this._currentMode) {
        return;
      }
      this._currentMode = mode;

      if (mode === FloorRenderMode.Hovering) {

        var fadeExt = this._getFadeExtension();
        if (fadeExt) {

          // Take control over CrossFade effect.
          // NOTE: As long as the mouse is hovering over the LevelsPanel, we assume that no one else overtakes the crossFade effect. If the mouse leaves the LevelsPanel
          //       the ghost-floors a fading out. If the fading is needed for something else at that time, we skip the fading and drop the ghost floors immediately.
          fadeExt.acquireControl('FloorSelector', function () {return _this._interruptFading();});

          // Render snapshot of selected floors into target 0
          fadeExt.setModelTargetIndexForAll(undefined); // render to main target
          this._applySelectedFloorSection(); // set cutplanes according to selected floor
          this._rollOverHighlightOff(); // keep mouse-over highlighting out of the snapshot
          this._setAOVisible(true); // Make sure that the selected floors are rendered with AO
          fadeExt.renderFadingImage(0); // render static snapshot of selected floors into extra target 0

          // show this snapshot at full opacity
          fadeExt.setCrossFadeOpacity(0, 1.0);

          // Render remaining floors...
          this._clearFloorSection();

          // ..into target 1
          fadeExt.setModelTargetIndexForAll(1);

          // before starting to fade-in the ghost-floors,
          // hide SAO. Otherwise, SAO of the ghost
          // floors would pop in at fade start.
          this._setAOVisible(false);

          // stop any prior fade-anim
          this._stopFadeAnim();

          // fade-in ghost floors (starting at the prior opacity)
          var onTimer = this._setGhostFloorOpactiy.bind(this);
          this._fadeAnim = avp.fadeValue(this._ghostFloorOpacity, MaxGhostFloorOpacity, GhostFloorFadingTime, onTimer);
        }
      } else if (mode === FloorRenderMode.Transition) {

        // protect ghost floors from clear
        var _fadeExt = this._getFadeExtension();
        if (_fadeExt) {
          _fadeExt.setClearEnabled(1, false);

          // render into target 0 again
          _fadeExt.setClearEnabled(0, true);
          _fadeExt.setModelTargetIndexForAll(0);

          // make sure that target 0 has full opacity to make sure that floor keeps visible after moving to target 0
          _fadeExt.setCrossFadeOpacity(0, 1.0);
        }

        // reactivate AO
        this._setAOVisible(true);

        // Render selected/moving floor...
        this._applySelectedFloorSection();

      } else if (mode === FloorRenderMode.Off) {

        // stop any prior fade-anim
        this._stopFadeAnim();

        // fade-out ghost floors (starting at current opacity)
        var _onTimer = this._setGhostFloorOpactiy.bind(this);
        var onFinished = this._leaveHoverMode.bind(this);
        this._fadeAnim = avp.fadeValue(this._ghostFloorOpacity, 0.0, GhostFloorFadingTime, _onTimer, onFinished);
      }
    } }, { key: "_moveToFloor", value: function _moveToFloor(

    floorIndex) {var _this2 = this;

      this._currentFloor = floorIndex;

      this._setMode(FloorRenderMode.Transition);

      var floor = this._floors[floorIndex];

      this._updateZLimits();

      var minElevStart = this._floorSectionMin === undefined ? this._zMinAllModels : this._floorSectionMin;
      var maxElevStart = this._floorSectionMax === undefined ? this._zMaxAllModels : this._floorSectionMax;
      var minElevEnd = floor ? floor.zMin : this._zMinAllModels;
      var maxElevEnd = floor ? floor.zMax : this._zMaxAllModels;

      var updateCutPlanes = function updateCutPlanes(unitTime) {
        var t = avp.smootherStep(unitTime);
        var minElev = avp.lerp(minElevStart, minElevEnd, t);
        var maxElev = avp.lerp(maxElevStart, maxElevEnd, t);

        _this2._setFloorSection(minElev, maxElev);

        // fade-out mouse over while animating
        var blendPass = _this2._renderer.getBlendPass();
        var uniform = blendPass.uniforms['highlightIntensity'];
        uniform.value = Math.min(uniform.value, 1.0 - t);
      };

      var onAnimEnd = function onAnimEnd() {
        // leave transition mode to hovering or off
        var mode = _this2._hovering ? FloorRenderMode.Hovering : FloorRenderMode.Off;
        _this2._setMode(mode);
      };

      // If another floor anim is in running, stop it first.
      this._stopFloorAnim();

      this._floorAnim = avp.fadeValue(0.0, 1.0, 0.5, updateCutPlanes, onAnimEnd);
    } }, { key: "_selectFloor", value: function _selectFloor(

    floorIndex) {

      // Make sure that a previous anim does not overwrite the cutplanes again.
      this._stopFloorAnim();

      this._currentFloor = floorIndex;

      // Note that zMin/zMax may also be undefined if no floor is selected
      var floor = this._floors[floorIndex];

      // Set min/maxElev from floor or set both to undefined (for 'no floor selected')
      var minElev = floor ? floor.zMin : undefined;
      var maxElev = floor ? floor.zMax : undefined;

      this._setFloorSection(minElev, maxElev);
    } }, { key: "_runFloorSelectorFilter", value: function _runFloorSelectorFilter()

    {
      this._previousFloor = this._currentFloor;

      // Make sure all previously hidden objects are set to visible again.
      this._floorSelectorFilter.clearFilter();

      if (this._floorFilterData && this._currentFloor !== undefined) {
        var floor = this._floors[this._currentFloor];
        this._floorSelectorFilter.filter(this._floorFilterData, floor);
      }
    } }, { key: "_runFloorSelectorFilterEventHandler", value: function _runFloorSelectorFilterEventHandler(

    event) {
      this._runFloorSelectorFilterEvent(event.model);
    } }, { key: "_runFloorSelectorFilterEvent", value: function _runFloorSelectorFilterEvent(

    model) {
      if (!model.isObjectTreeLoaded()) {
        return;
      }
      if (!(this._floorFilterData && this._currentFloor !== undefined)) {
        // Handles the case when a level was deactivated while the model was not visible.
        // When activating again the model, we need to make sure that the previously
        // filtered elements are set to visible again.
        this._floorSelectorFilter.clearFilter();
        return;
      }
      this._runFloorSelectorFilter();
    } }, { key: "_runModelUnloadingEventHandler", value: function _runModelUnloadingEventHandler(

    event) {
      this._runModelUnloadingEvent(event.model);
    } }, { key: "_runModelUnloadingEvent", value: function _runModelUnloadingEvent(

    model) {
      if (this._floorFilterData && this._currentFloor !== undefined) {
        this._floorSelectorFilter.unhideModel(model);
      }
    } }, { key: "floorData", get: function get() {return this._floors;}, set: function set(floors) {// always reset the floor selector when floors data changes to avoid inconstancy
      this.resetState();this._floors = Array.isArray(floors) ? floors : [];} }, { key: "floorFilterData", get: function get() {return this._floorFilterData;}, set: function set(floorFilterData) {this._floorFilterData = floorFilterData;} }, { key: "currentFloor", get: function get() {return this._currentFloor;} }]);return FloorSelector;}();

FloorSelector.AllFloors = AllFloors;
FloorSelector.NoFloor = NoFloor;

FloorSelector.CURRENT_FLOOR_CHANGED = "currentFloorChanged";

namespace.FloorSelector = FloorSelector;

/***/ }),

/***/ "./extensions/AEC/levels/FloorSelectorFilter.js":
/*!******************************************************!*\
  !*** ./extensions/AEC/levels/FloorSelectorFilter.js ***!
  \******************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return FloorSelectorFilter; });
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}

var namespace = AutodeskNamespace('Autodesk.AEC');

// The FloorSelectorFilter provides functionality to additionally apply object filtering
// by dbIds on level selection.
//
var
FloorSelectorFilter = /*#__PURE__*/function () {

  // @param {Viewer3D} viewer
  function FloorSelectorFilter(viewer) {_classCallCheck(this, FloorSelectorFilter);
    this._viewer = viewer;
    // Contains all dbIds per model used to un-hide the objects whenever another level gets selected.
    this._dbIdsToUnhide = new Map();
    this._cache = {};
  }

  // Filter all elements by dbIds on level selection.
  //  @param {Object}   floorFilterData   - A floor filter data object containing all dbIds per model and an optional level height factor.
  //  @param {Object}   floor             - A floor.
  _createClass(FloorSelectorFilter, [{ key: "filter", value: function filter(floorFilterData, floor) {var _this = this;
      if (!floorFilterData) {
        throw new Error('floorFilterData cannot be undefined.');
      }
      if (!(floorFilterData.modelsDbIds instanceof Map)) {
        throw new Error('floorFilterData.modelsDbIds has to be a Map.');
      }
      if (!floor) {
        throw new Error('floor cannot be undefined.');
      }

      // Get the level height factor and also do some basic number checks.
      var levelHeightFactor = this._getLevelHeightFactor(floorFilterData.levelHeightFactor);

      // All Floor and Ceiling db ids per model to hide.
      var modelsDbIds = floorFilterData.modelsDbIds;

      // Do nothing in case no db ids are set.
      if (!this._hasModelDbIds(modelsDbIds)) {
        return;
      }

      var minZ = floor.zMin;
      var maxZ = floor.zMax;

      // Calculate the new minZ/maxZ values of the level boundary used to spatially filter the Floor and
      // Ceiling elements.
      // 1. The lower boundary value (zMin) is moved up by the factor of the level height, because the Ceiling
      //    elements we want to filter are located in the upper part of the level.
      // 2. The upper boundary value (zMax) is moved up by 10% of the level height, because in some models
      //    this helps to also remove floors which would be still shown otherwise.
      var newMinZ = minZ + (maxZ - minZ) * levelHeightFactor;
      var newMaxZ = maxZ + (maxZ - minZ) * 0.1;

      // Setup cache for each floor.
      if (!this._cache[floor.name]) {
        this._cache[floor.name] = {};
      }

      var modelQueue = this._viewer.impl.modelQueue();
      var models = modelQueue.getModels();var _loop2 = function _loop2(

      m, l) {
        var model = models[m];

        if (!model.visibilityManager) {
          console.warn("The VisibilityManager of the model with ID = ".concat(model.id, " is not yet initialized."));
          return "break";
        }

        // Try to get the db ids for a specific level and model from the cache.
        if (_this._cache[floor.name][model.id]) {
          var cachedDbIds = _this._cache[floor.name][model.id];
          if (cachedDbIds.size > 0) {
            _this.hideDbIds(model, cachedDbIds);
          }
          return "continue";
        }

        var instanceTree = model.getInstanceTree();
        if (!instanceTree) {
          console.warn("The instanceTree of the model with ID = ".concat(model.id, " is not yet initialized."));
          return "continue";
        }
        var fragmentList = model.getFragmentList();

        var dbIdsToHide = new Set();
        var dbIds = _this._getModelDbIds(modelsDbIds, model);
        if (!dbIds) {
          return "continue";
        }

        dbIds.forEach(function (dbId) {
          var nodeBox = new Float32Array(6);
          instanceTree.getNodeBox(dbId, nodeBox);

          var nodeBoxMinZ = nodeBox[2];
          var nodeBoxMaxZ = nodeBox[5];

          if (nodeBoxMinZ >= newMinZ && nodeBoxMinZ <= newMaxZ ||
          nodeBoxMaxZ >= newMinZ && nodeBoxMaxZ <= newMaxZ ||
          nodeBoxMinZ <= newMinZ && nodeBoxMaxZ >= newMaxZ) {
            dbIdsToHide.add(dbId);
          }
        });

        if (dbIdsToHide.size > 0) {
          _this.hideDbIds(model, dbIdsToHide);
        }

        _this._cache[floor.name][model.id] = dbIdsToHide;};_loop: for (var m = 0, l = models.length; m < l; m++) {var _ret = _loop2(m, l);switch (_ret) {case "break":break _loop;case "continue":continue;}
      }
    } }, { key: "hideDbIds", value: function hideDbIds(

    model, dbIds) {
      if (!model.visibilityManager) {
        return;
      }

      dbIds.forEach(function (id) {
        model.visibilityManager.setNodeOff(id, true);
      });

      // Collect all dbIds per model, so we can un-hide them later on again.
      this._collectDbIdsPerModel(model, dbIds);
    }

    // Un-hides all objects (using the dbId) per model.
  }, { key: "clearFilter", value: function clearFilter() {
      if (this._dbIdsToUnhide.size === 0) {
        return;
      }

      this._dbIdsToUnhide.forEach(function (dbIds, model) {
        // Handles the case when the model is not visible and the level isolation is deactivated.
        if (!model.visibilityManager) {
          return;
        }

        dbIds.forEach(function (id) {
          model.visibilityManager.setNodeOff(id, false);
        });

        // Only remove the model dbIds if they are successfully set to visible.
        this._dbIdsToUnhide.delete(model);
      }.bind(this));
    }

    // Un-hides only one model. It's all we can do, as the model.visibilityManager is null,
    // that is we can not call setNodeOff function again
  }, { key: "unhideModel", value: function unhideModel(model) {
      this._dbIdsToUnhide.delete(model);
    } }, { key: "_collectDbIdsPerModel", value: function _collectDbIdsPerModel(

    model, dbIdsToUnhide) {
      if (this._dbIdsToUnhide.has(model)) {
        var dbIds = this._dbIdsToUnhide.get(model);var _iteratorNormalCompletion = true;var _didIteratorError = false;var _iteratorError = undefined;try {
          for (var _iterator = dbIdsToUnhide[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {var dbId = _step.value;
            dbIds.add(dbId);
          }} catch (err) {_didIteratorError = true;_iteratorError = err;} finally {try {if (!_iteratorNormalCompletion && _iterator.return != null) {_iterator.return();}} finally {if (_didIteratorError) {throw _iteratorError;}}}
      } else {
        this._dbIdsToUnhide.set(model, dbIdsToUnhide);
      }
    } }, { key: "_getModelDbIds", value: function _getModelDbIds(

    modelsDbIds, model) {
      return modelsDbIds.get(model);
    } }, { key: "_hasModelDbIds", value: function _hasModelDbIds(

    modelsDbIds) {

      if (modelsDbIds.size === 0) {
        return false;
      }var _iteratorNormalCompletion2 = true;var _didIteratorError2 = false;var _iteratorError2 = undefined;try {

        for (var _iterator2 = modelsDbIds.values()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {var dbIds = _step2.value;
          if (dbIds && dbIds.length > 0) {
            return true;
          }
        }} catch (err) {_didIteratorError2 = true;_iteratorError2 = err;} finally {try {if (!_iteratorNormalCompletion2 && _iterator2.return != null) {_iterator2.return();}} finally {if (_didIteratorError2) {throw _iteratorError2;}}}

      return false;
    } }, { key: "_getLevelHeightFactor", value: function _getLevelHeightFactor(

    levelHeightFactor) {
      if (levelHeightFactor === undefined) {
        // Return default factor.
        return 0.5;
      }

      if (typeof levelHeightFactor !== 'number') {
        throw new Error('floorFilterData.levelHeightFactor has to be a number');
      }
      if (levelHeightFactor < 0 || levelHeightFactor >= 1) {
        throw new Error('floorFilterData.levelHeightFactor has to be a number between 0-1.');
      }

      return levelHeightFactor;
    }

    // Hides all dbIds in a model that are currently expected to be hidden. 
  }, { key: "reApplyFilter", value: function reApplyFilter(model) {
      var dbIds = this._dbIdsToUnhide.get(model);
      var visMan = model.visibilityManager;
      if (!dbIds || !visMan) {
        return;
      }

      dbIds.forEach(function (id) {
        visMan.setNodeOff(id, true);
      });
    } }, { key: "isVisible", value: function isVisible(

    model, dbId) {
      var dbIds = this._dbIdsToUnhide.get(model);
      return !dbIds || !dbIds.has(dbId);
    } }]);return FloorSelectorFilter;}();


namespace.FloorSelectorFilter = FloorSelectorFilter;

/***/ }),

/***/ "./extensions/AEC/levels/LevelUtils.js":
/*!*********************************************!*\
  !*** ./extensions/AEC/levels/LevelUtils.js ***!
  \*********************************************/
/*! exports provided: transformLevelsByMatrix, transformLevels, modelToLevels, aecModelDataToLevels, chooseMainModel, modelDataOccluders */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformLevelsByMatrix", function() { return transformLevelsByMatrix; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformLevels", function() { return transformLevels; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "modelToLevels", function() { return modelToLevels; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "aecModelDataToLevels", function() { return aecModelDataToLevels; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "chooseMainModel", function() { return chooseMainModel; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "modelDataOccluders", function() { return modelDataOccluders; });

function getProjectElevation(level) {
  var ext = level.extension;

  if (ext && ext.hasOwnProperty('projectElevation'))
  return ext.projectElevation;

  return level.elevation;
}

function transformLevelsByMatrix(levels, refPointTransformation) {

  var v = new THREE.Vector3();
  var transformByMatrix = function transformByMatrix(value) {
    v.set(0, 0, value);
    v.applyMatrix4(refPointTransformation);
    return v.z;
  };

  levels.forEach(function (currentLevel) {
    currentLevel.zMin = transformByMatrix(currentLevel.zMin);
    currentLevel.zMax = transformByMatrix(currentLevel.zMax);
  });
}


// transform is given as 12 floats
function transformLevels(levels, refPointTransformation) {
  if (!refPointTransformation)
  return;

  // get transform as THREE.Matrix4
  var matrix = Autodesk.Viewing.BubbleNode.readMatrixFromArray12(refPointTransformation);
  transformLevelsByMatrix(levels, matrix);
}

function modelToLevels(model) {

  var bubbleNode = model.getDocumentNode();
  var modelData = bubbleNode.getAecModelData();

  if (!modelData || !modelData.levels || !modelData.levels.length) {
    return [];
  }

  return aecModelDataToLevels(modelData);
}

function aecModelDataToLevels(aecModelData, placementTf) {
  // levels are sorted ascending

  // we have to handle the building story flag of a Revit level
  // filter out all Revit levels which do not have building story set to true
  var filteredLevels = aecModelData.levels.filter(function (l) {
    var ext = l.extension;

    if (!ext)
    return true;

    //So.... if it has no buildingStory property, it's a building story...
    if (!ext.hasOwnProperty('buildingStory'))
    return true;

    return ext.buildingStory;
  });

  var levels = [];

  var count = filteredLevels.length;
  filteredLevels.forEach(function (currentLevel, index) {

    var nextElevation = undefined;
    if (index + 1 < count) {
      nextElevation = getProjectElevation(filteredLevels[index + 1]);
    } else
    {
      // for the topmost floor, we must use its height to determine the next boundary
      var topLevel = filteredLevels[filteredLevels.length - 1];
      var topLevelElevation = getProjectElevation(topLevel);
      nextElevation = topLevelElevation + topLevel.height;
    }

    //Explanation from design-collaboration repo:
    // Hint: the idea to move the level zMin value an inch down is to make sure that the
    // end-user can also see the bottom floor. Otherwise in some cases the floor would just
    // be cut-away by the floor selection. This value was defined after experimenting with
    // several models and maybe needs adjustment in the future.
    var zOffsetHack = 1 / 12;

    levels.push({
      index: levels.length,
      name: currentLevel.name,
      zMin: getProjectElevation(currentLevel) - zOffsetHack,
      zMax: nextElevation,
      guid: currentLevel.guid });

  });

  // If the model is known, use its attached transform. This variant works with any loadOptions. 
  if (placementTf) {
    transformLevelsByMatrix(levels, placementTf);
  } else {
    // If the model is not known, we assume that no zOffset is applied. This is only
    // true when using applyRefPoint=true and a gobalOffset with z=0.
    transformLevels(levels, aecModelData.refPointTransformation);
  }
  return levels;
}

function chooseMainModel(viewer) {

  var models = viewer.impl.modelQueue().getModels();
  var mainModel = null;
  var mainModelSize = -1;
  models.forEach(function (model) {

    if (model.is2d())
    return;

    var bubbleNode = model.getDocumentNode();

    if (!bubbleNode)
    return;

    var aecModelData = bubbleNode.getAecModelData();

    if (!aecModelData)
    return;

    if (bubbleNode.data.size > mainModelSize) {
      mainModel = model;
      mainModelSize = bubbleNode.data.size;
    }
  });
  return mainModel;
}

function modelDataOccluders(viewer) {

  var models = viewer.impl.modelQueue().getModels();

  var occludersPerModel = new Map();

  models.forEach(function (model) {

    if (model.is2d())
    return;

    var bubbleNode = model.getDocumentNode();
    var aecModelData = bubbleNode.getAecModelData();
    if (!aecModelData)
    return;

    occludersPerModel.set(model, aecModelData.levelOccluderIds);
  });

  return { modelsDbIds: occludersPerModel };
}

/***/ }),

/***/ "./extensions/AEC/levels/LevelsExtension.js":
/*!**************************************************!*\
  !*** ./extensions/AEC/levels/LevelsExtension.js ***!
  \**************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return LevelsExtension; });
/* harmony import */ var _FloorSelector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./FloorSelector */ "./extensions/AEC/levels/FloorSelector.js");
/* harmony import */ var _LevelUtils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./LevelUtils */ "./extensions/AEC/levels/LevelUtils.js");
/* harmony import */ var _ui_ListPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../ui/ListPanel */ "./extensions/AEC/ui/ListPanel.js");
function _typeof(obj) {if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {_typeof = function _typeof(obj) {return typeof obj;};} else {_typeof = function _typeof(obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};}return _typeof(obj);}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function _createClass(Constructor, protoProps, staticProps) {if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor;}function _possibleConstructorReturn(self, call) {if (call && (_typeof(call) === "object" || typeof call === "function")) {return call;}return _assertThisInitialized(self);}function _getPrototypeOf(o) {_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {return o.__proto__ || Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass, superClass) {if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function");}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } });if (superClass) _setPrototypeOf(subClass, superClass);}function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);}function _assertThisInitialized(self) {if (self === void 0) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}

var av = Autodesk.Viewing,avu = av.UI;
var namespace = AutodeskNamespace('Autodesk.AEC');
var myExtensionName = 'Autodesk.AEC.LevelsExtension';





// Options:
//   @param {bool} [autoDetectAecModelData = true]
//         Level selection requires data about existing floors. By default (true), these are extracted automatically:
//          - For a single model, we get them by calling getAecModelData() on the document node.
//          - If multiple models with aecModelData are visible, we choose the largest one to define the levels.
//
//         If set to false, an application can (and has to) call setAecModelData() explicitly instead.
var LevelsExtension = /*#__PURE__*/function (_av$Extension) {_inherits(LevelsExtension, _av$Extension);
  function LevelsExtension(viewer, options) {var _this;_classCallCheck(this, LevelsExtension);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(LevelsExtension).call(this, viewer, options));

    _this.container = _this.options.panelUIContainers && _this.options.panelUIContainers.levelsPanel;

    _this._onCameraMoved = _this._onCameraMoved.bind(_assertThisInitialized(_assertThisInitialized(_this)));
    _this._onMove = undefined;

    _this._subscribedForLocationUpdates = false;
    _this._currentLevel = undefined;return _this;
  }_createClass(LevelsExtension, [{ key: "setOnCameraMove", value: function setOnCameraMove(

    func) {
      if (!this._subscribedForLocationUpdates && func) {
        this.viewer.addEventListener(av.CAMERA_CHANGE_EVENT, this._onCameraMoved);
        this._subscribedForLocationUpdates = true;
        this._onMove = func;
      } else if (!func) {
        this.viewer.removeEventListener(av.CAMERA_CHANGE_EVENT, this._onCameraMoved);
        this._subscribedForLocationUpdates = false;
        this._onMove = null;
        this._currentLevel = null;
      }
    } }, { key: "_onCameraMoved", value: function _onCameraMoved()

    {
      if (!this._onMove) {
        return;
      }
      var currentLevel = this._mapCameraToLevel();

      if (!currentLevel)
      return;

      if (!this._currentLevel || currentLevel.guid !== this._currentLevel.guid) {
        this._currentLevel = currentLevel;
        this._onMove(currentLevel);
      }
    } }, { key: "_mapCameraToLevel", value: function _mapCameraToLevel()

    {
      var floors = this.floorSelector.floorData;
      if (!floors.length) {
        return;
      }

      var currentElevation = this.viewer.impl.camera.position.z;

      if (currentElevation < floors[0].zMin) {
        return floors[0];
      } else
      if (currentElevation > floors[floors.length - 1].zMax) {
        return floors[floors.length - 1];
      } else
      {
        return floors.find(function (f) {return f.zMin <= currentElevation && f.zMax >= currentElevation;});
      }
    } }, { key: "_createUI", value: function _createUI()

    {var _this2 = this;
      this.levelsButton = new avu.Button("toolbar-levelsTool");
      this.levelsButton.setToolTip('Levels');
      this.levelsButton.icon.innerHTML = createLevelsIcon();

      // make sure inspect tools is visible
      var toolbar = this.viewer.getToolbar(false);
      var modelTools = toolbar.getControl(av.TOOLBAR.MODELTOOLSID);

      //Add our button to the toolbar if host app did not ask to render UI in some other place
      if (modelTools && !this.container) {
        modelTools.addControl(this.levelsButton);
      }

      this.levelsPanel = new _ui_ListPanel__WEBPACK_IMPORTED_MODULE_2__["ListPanel"](this.container || this.viewer.container, 'LevelsPanel-' + this.viewer.id, 'Levels');

      if (!this.container) {
        // This ensures that the Panel keeps visible within the viewer canvas on resize.
        this.viewer.addPanel(this.levelsPanel);
      }


      // Keep button-state consistent when pressing panel close
      this.levelsPanel.addVisibilityListener(function (visible) {
        _this2.levelsButton.setState(visible ? avu.Button.State.ACTIVE : avu.Button.State.INACTIVE);
      });

      // allow client app to be notified on panel close
      this.levelsPanel.closer.addEventListener('click', function () {
        if (_this2.onPanelVisibilityToggled) {
          _this2.onPanelVisibilityToggled(false);
        }
      });

      this.levelsPanel.addEventListener(_ui_ListPanel__WEBPACK_IMPORTED_MODULE_2__["ListPanelEvents"].ITEM_MOUSE_ENTER, function (event) {

        var levelIndex = event.item.index;

        // Selecting an already selected level again will unselect => i.e. all Floors will be shown.
        // Correspondingly, we trigger rollover highlighting for all floors when hovering over the selected level.
        if (levelIndex === _this2.floorSelector.currentFloor) {
          levelIndex = _FloorSelector__WEBPACK_IMPORTED_MODULE_0__["default"].AllFloors;
        }

        _this2.floorSelector.rollOverFloor(levelIndex);
        _this2.hoveredFloor = levelIndex;
      });

      this.levelsPanel.addEventListener(_ui_ListPanel__WEBPACK_IMPORTED_MODULE_2__["ListPanelEvents"].ITEM_MOUSE_LEAVE, function (event) {
        if (_this2.hoveredFloor === event.item.index) {
          _this2.hoveredFloor = undefined;
          _this2.floorSelector.rollOverFloor(_FloorSelector__WEBPACK_IMPORTED_MODULE_0__["default"].NoFloor);
        }
      });

      this.levelsPanel.addEventListener(_ui_ListPanel__WEBPACK_IMPORTED_MODULE_2__["ListPanelEvents"].ITEM_SELECT, function (event) {
        // on item selected
        var levelIndex = event.item.index !== _this2.floorSelector.currentFloor ? event.item.index : undefined;
        _this2.floorSelector.selectFloor(levelIndex, true);
      });

      // Handle hovering over panel
      this.levelsPanel.container.addEventListener("mouseenter", function () {return _this2.floorSelector.enterHoverMode();});
      this.levelsPanel.container.addEventListener("mouseleave", function () {return _this2.floorSelector.exitHoverMode();});

      // Keep selected item in-sync with selected Floor
      this.floorSelector.addEventListener(
      _FloorSelector__WEBPACK_IMPORTED_MODULE_0__["default"].CURRENT_FLOOR_CHANGED,
      function () {return _this2.levelsPanel.updateItemStates();});


      this.levelsPanel.setItemHandlers(
      function (item) {return item.index === _this2.floorSelector.currentFloor;},
      function (item) {return item.text;});


      // Connect levelsButton
      this.levelsButton.onClick = function () {
        var visible = !_this2.levelsPanel.isVisible();
        _this2.levelsPanel.setVisible(visible);

        // allow client app to be notified
        if (_this2.onPanelVisibilityToggled) {
          _this2.onPanelVisibilityToggled(visible);
        }
      };
    }

    // If placementTf is undefined, we use the refPointTransform of aecModelData.
    // Note that this is correct when using applyRefPoint=true and a globalOffset with z=0
    // for the model load options.
  }, { key: "setAecModelData", value: function setAecModelData(aecModelData, placementTf) {

      if (aecModelData !== this.aecModelData) {

        this.aecModelData = aecModelData;

        if (aecModelData) {
          // init level data
          this.floorSelector.floorData = Object(_LevelUtils__WEBPACK_IMPORTED_MODULE_1__["aecModelDataToLevels"])(aecModelData, placementTf);
        } else {
          this.floorSelector.floorData = [];
        }

        var levels = this.floorSelector.floorData;
        var items = [];
        for (var i = 0; i < levels.length; i++) {
          var level = levels[i];
          items.push({
            text: level.name,
            index: i });

        }

        // list items in reverse order, because aecModelData levels are sorted by increasing z
        items.reverse();
        this.levelsPanel.setItems(items);

        this._updateOccluderData();
      }
    } }, { key: "_updateOccluderData", value: function _updateOccluderData()

    {
      // Make sure that occluder data is known if a main model is specified
      var occludersPerModel = this.aecModelData ? Object(_LevelUtils__WEBPACK_IMPORTED_MODULE_1__["modelDataOccluders"])(this.viewer) : undefined;
      this.floorSelector.floorFilterData = occludersPerModel;
    } }, { key: "load", value: function load()

    {var _this3 = this;
      this.floorSelector = new _FloorSelector__WEBPACK_IMPORTED_MODULE_0__["default"](this.viewer);

      this.updateFloorSelector = function () {
        // auto-detect main model if not disabled
        var autoDetect = _this3.options.autoDetectAecModelData !== false;
        if (autoDetect) {
          var model = Object(_LevelUtils__WEBPACK_IMPORTED_MODULE_1__["chooseMainModel"])(_this3.viewer);
          var bubbleNode = model && model.getDocumentNode();
          var aecModelData = bubbleNode && bubbleNode.getAecModelData();

          // provde placement matrix as well.
          var placementTf = model && model.myData.placementWithOffset;
          _this3.setAecModelData(aecModelData, placementTf);
        }

        _this3._updateOccluderData();

        // Make sure that cutplanes are disabled when in 2d views and reactivated in 3d
        // Todo: Check if we can move the MODEL_ADDED event at the end of addModel, so that we could simply use viewer.is2d here.
        var is3d = _this3.viewer.getVisibleModels().some(function (model) {return model.is3d();});
        _this3.floorSelector.setEnabled(is3d);
      };

      this.viewer.addEventListener(av.MODEL_ROOT_LOADED_EVENT, this.updateFloorSelector);
      this.viewer.addEventListener(av.MODEL_UNLOADED_EVENT, this.updateFloorSelector);
      this.viewer.addEventListener(av.MODEL_ADDED_EVENT, this.updateFloorSelector);

      this._createUI();
      this.updateFloorSelector();

      return true;
    } }, { key: "unload", value: function unload()

    {
      if (!this.container) {
        this.viewer.removePanel(this.levelsPanel);
      }
      this.floorSelector.selectFloor(undefined, false);
      this.levelsPanel = null;

      if (this.updateFloorSelector) {
        this.viewer.removeEventListener(av.MODEL_ROOT_LOADED_EVENT, this.updateFloorSelector);
        this.viewer.removeEventListener(av.MODEL_UNLOADED_EVENT, this.updateFloorSelector);
        this.viewer.removeEventListener(av.MODEL_ADDED_EVENT, this.updateFloorSelector);
        this.updateFloorSelector = null;
      }

      if (this._subscribedForLocationUpdates) {
        this.viewer.removeEventListener(av.CAMERA_CHANGE_EVENT, this._onCameraMoved);
        this._onMove = null;
        this._currentLevel = null;
      }

      this.floorSelector = null;

      return true;
    } }]);return LevelsExtension;}(av.Extension);


var createLevelsIcon = function createLevelsIcon() {
  return [
  '<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">',
  '<g stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">',
  '<path d="M4 8 L12 3 L 20 8 L12 13Z"/>',
  '<path d="M4 12 L12 17 L 20 12"/>',
  '<path d="M4 16 L12 21 L 20 16"/>Ä',
  '</g>',
  '</svg>'].
  join('');
};

namespace.LevelsExtension = LevelsExtension; // Makes it easier to get e.g. the version

// Register the extension with the extension manager.
Autodesk.Viewing.theExtensionManager.registerExtension(myExtensionName, LevelsExtension);

/***/ }),

/***/ "./extensions/AEC/ui/ListPanel.css":
/*!*****************************************!*\
  !*** ./extensions/AEC/ui/ListPanel.css ***!
  \*****************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {


var content = __webpack_require__(/*! !../../../node_modules/css-loader!./ListPanel.css */ "./node_modules/css-loader/index.js!./extensions/AEC/ui/ListPanel.css");

if(typeof content === 'string') content = [[module.i, content, '']];

var transform;
var insertInto;



var options = {"hmr":true}

options.transform = transform
options.insertInto = undefined;

var update = __webpack_require__(/*! ../../../node_modules/style-loader/lib/addStyles.js */ "./node_modules/style-loader/lib/addStyles.js")(content, options);

if(content.locals) module.exports = content.locals;

if(false) {}

/***/ }),

/***/ "./extensions/AEC/ui/ListPanel.js":
/*!****************************************!*\
  !*** ./extensions/AEC/ui/ListPanel.js ***!
  \****************************************/
/*! exports provided: ListPanelEvents, ListPanel */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ListPanelEvents", function() { return ListPanelEvents; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ListPanel", function() { return ListPanel; });

var av = Autodesk.Viewing;
var avu = Autodesk.Viewing.UI;


var ListPanelEvents = {

  /**
                                * Fired when clicking on an item. (not fired when setting current item per code)
                                *  @property {Object} item  - data item being selected.
                                */
  ITEM_SELECT: 'itemSelect',

  /**
                              * @property {Object} item - data item being selected.
                              */
  ITEM_MOUSE_ENTER: 'itemMouseEnter',
  ITEM_MOUSE_LEAVE: 'itemMouseLeave' };


function ListPanel(parentContainer, id, title, options) {

  avu.DockingPanel.call(this, parentContainer, id, title, options);

  av.EventDispatcher.prototype.apply(this);

  this.container.classList.add('list-panel');
  this.container.dockRight = true;
  this.createScrollContainer({ left: false, heightAdjustment: 65, marginTop: 0 });
}

ListPanel.prototype = Object.create(avu.DockingPanel.prototype);

// @param {Object[]} items - Array order defines display order top-down.
ListPanel.prototype.setItems = function (items) {

  this.buttons = [];
  this.items = items;

  // remove old list
  if (this.listDiv) {
    this.scrollContainer.removeChild(this.listDiv);
  }
  this.listDiv = document.createElement('div');
  this.listDiv.classList.add('itemList');

  this.scrollContainer.appendChild(this.listDiv);

  var scope = this;

  var createButton = function createButton(item) {

    var itemText = scope._getItemText ? scope._getItemText(item) : '<no item text>';

    var button = document.createElement('div');
    button.classList.add('listItem');
    button.item = item;
    button.setAttribute('title', itemText);

    button.addEventListener('click', function () {
      scope.fireEvent({
        type: ListPanelEvents.ITEM_SELECT,
        item: item });

    });
    button.addEventListener('mouseenter', function () {
      scope.fireEvent({
        type: ListPanelEvents.ITEM_MOUSE_ENTER,
        item: item });

    });
    button.addEventListener('mouseleave', function () {
      scope.fireEvent({
        type: ListPanelEvents.ITEM_MOUSE_LEAVE,
        item: item });

    });

    var textSpan = document.createElement('span');
    textSpan.innerHTML = itemText;
    textSpan.classList.add("text");

    // This container DIV is required to enable proper text fade-out for long texts.
    var textContainerDiv = document.createElement('div');
    textContainerDiv.classList.add("textContainer");
    textContainerDiv.appendChild(textSpan);
    button.appendChild(textContainerDiv);

    var warnSpan = document.createElement('span');
    warnSpan.classList.add("list-panel-item-warning");
    button.appendChild(warnSpan);
    button.warnSpan = warnSpan;

    var checkSpan = document.createElement('span');
    checkSpan.classList.add("icon");
    button.appendChild(checkSpan);

    return button;
  };

  for (var index = 0; index < items.length; index++) {

    var item = items[index];
    var button = createButton(item);

    this.listDiv.appendChild(button);
    this.buttons.push(button);
  }

  this.updateItemStates();
};

ListPanel.prototype.updateItemStates = function () {

  if (!this.buttons) {
    return;
  }
  for (var i = 0; i < this.buttons.length; i++) {

    // set/unset checkmark
    var button = this.buttons[i];
    button.classList.remove("selected");
    if (this._isSelected && this._isSelected(button.item)) {
      button.classList.add("selected");
    }

    // set/unset warning symbol
    var warnText = this._getWarningText && this._getWarningText(button.item);
    button.warnSpan.style.visibility = warnText ? 'visible' : 'hidden';
    button.warnSpan.setAttribute('title', warnText || '');
  }
};

// Set functions to define how to handle each item
//  @param {function(item)} isSelected       - takes a list item (see setItems) and returns true for 'selected state'
//  @param {function(item)} getItemText      - returns the text to be displayed
//  @param {function(item)} [getWarningText] - Optional: Display a warning symbol. Function defines tooltip text.
ListPanel.prototype.setItemHandlers = function (isSelected, getItemText, getWarningText) {
  this._isSelected = isSelected;
  this._getItemText = getItemText;
  this._getWarningText = getWarningText;
  this.updateItemStates();
};

avu.ListPanelEvents = ListPanelEvents;
avu.ListPanel = ListPanel;

/***/ }),

/***/ "./node_modules/css-loader/index.js!./extensions/AEC/CanvasBookmark/CanvasBookmark.css":
/*!************************************************************************************!*\
  !*** ./node_modules/css-loader!./extensions/AEC/CanvasBookmark/CanvasBookmark.css ***!
  \************************************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false);
// imports


// module
exports.push([module.i, "/*\nhttps://stackoverflow.com/questions/27900053/css-transition-with-visibility-not-working\n\nVisibility is an animatable property according to the spec, but transitions on visibility do not work gradually, as one might expect.\nInstead transitions on visibility delay hiding an element. On the other hand making an element visible works immediately.\nThis is as it is defined by the spec (in the case of the default timing function) and as it is implemented in the browsers.\n\n    ==> transition: visibility 0.7s, opacity 0.7s;\n*/\n.canvas-bookmark.adsk-button, .clustered-canvas-bookmark.adsk-button, .declustered-canvas-bookmark.adsk-button {\n    position: absolute;\n    left: 0px;\n    top:  0px;\n    border-style: none !important; /* Avoid border on button-hover */\n    color: white;\n    margin: none;\n    padding: 0px;\n    transition: visibility 0.5s, opacity 0.5s;\n    opacity: 0;\n    visibility: hidden;\n}\n\n.canvas-bookmark.adsk-button {\n    width:  22px;\n    height: 22px;\n}\n\n.clustered-canvas-bookmark.adsk-button {\n    width:  29px;\n    height: 29px;\n}\n\n.declustered-canvas-bookmark.adsk-button {\n    width:  29px;\n    height: 29px;\n    color: lightgrey;\n}\n\n.canvas-bookmark.visible {\n    opacity: 1;\n    visibility: visible;\n}\n\n.clustered-canvas-bookmark.visible {\n    opacity: 1;\n    visibility: visible;\n}\n", ""]);

// exports


/***/ }),

/***/ "./node_modules/css-loader/index.js!./extensions/AEC/DropMe/DropMe.css":
/*!********************************************************************!*\
  !*** ./node_modules/css-loader!./extensions/AEC/DropMe/DropMe.css ***!
  \********************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false);
// imports


// module
exports.push([module.i, ".camera-selector {\n    width: 0;\n    height: 0;\n    border-left: 50px solid transparent;\n    border-right: 50px solid transparent;\n    border-top: 100px solid #0696D7;\n    border-radius: 50%;\n    transform-origin: bottom center;\n    position: absolute;\n    opacity: 0.8;\n    pointer-events: none;\n    z-index: 1;\n}\n\n.camera-selector-position {\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: #0696D7;\n    position: absolute;\n    opacity: 0.8;\n    pointer-events: none;\n    z-index: 1;\n    transform: scale(1,1);\n    transition: transform 3s ease-in;\n}\n\n.camera-selector-position--teleporting {\n    transform: scale(0,0);\n}\n\n.camera-selector-background {\n    width: 200px;\n    height: 200px;\n    background-color: #0696D7;\n    opacity: 0.2;\n    position: absolute;\n    pointer-events: none;\n    z-index: 0;\n    transform: translate(-100px, -100px);\n    border-radius: 50%;\n}\n\n/* mimic issues UI guidance for now as it was the only extension, featuring guidance so far */\n.dropme-guidenace-ui {\n    display: flex;\n    position: absolute;\n    left: 50%;\n    top: 20px;\n    padding: 10px 20px;\n    transform: translate(-50%, 0);\n    align-items: center;\n    border: 1px solid #9ec8f6;\n    border-radius: 4px;\n    background-color: #edf5fd;\n    color: #039be5;\n    font-size: 12px;\n    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);\n    opacity: 1;\n    z-index: 999;\n    overflow-y: hidden;\n}\n", ""]);

// exports


/***/ }),

/***/ "./node_modules/css-loader/index.js!./extensions/AEC/Minimap3D/Minimap3D.css":
/*!**************************************************************************!*\
  !*** ./node_modules/css-loader!./extensions/AEC/Minimap3D/Minimap3D.css ***!
  \**************************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false);
// imports


// module
exports.push([module.i, "/*\nhttps://stackoverflow.com/questions/27900053/css-transition-with-visibility-not-working\n\nVisibility is an animatable property according to the spec, but transitions on visibility do not work gradually, as one might expect.\nInstead transitions on visibility delay hiding an element. On the other hand making an element visible works immediately.\nThis is as it is defined by the spec (in the case of the default timing function) and as it is implemented in the browsers.\n\n    ==> transition: visibility 0.7s, opacity 0.7s;\n*/\n.minimap3D {\n    width: 0px;\n    height: 0px;\n    right: 10px;\n    top: 10px;\n    position: absolute;\n    transition: visibility 0.7s, opacity 0.7s;\n    opacity: 0;\n    visibility: hidden;\n    overflow: hidden; /* important for scrolling: the map image contains the whole map but is cropped to the visible area by the parent widget */\n    background: rgba(255,255,255,0.2);\n}\n\n.minimap3D.visible {\n    opacity: 1;\n    visibility: visible;\n}\n\n/* Note that border changes require to update the anchor point in Minimap.js too */\n.player-widget {\n    width:  0px;\n    height: 0px;\n    position: absolute;\n    transition: opacity 0.7s;\n    opacity: 0;\n}\n\n.player-frustum {\n    border-left: 20px solid transparent;\n    border-right: 20px solid transparent;\n    border-top: 40px solid #3590e9;\n    border-radius: 50%;\n    opacity: 0.4;\n    width:  0px;\n    height: 0px;\n    position: absolute;\n    transform-origin: bottom center;\n }\n\n.player-widget.visible {\n    opacity: 0.7;\n}\n\n.player-position-fill {\n    width: 10px;\n    height: 10px;\n    /* Move circle center to the tip of the frustum shape */\n    left: 15px; /* = (playerFrustum.border-left - width/2)  */\n    top: 35px; /* = (playerFrustum.border-top  - height/2) */\n    position: absolute;\n    border-radius: 50%;\n    background-color: #3590e9;\n    box-shadow: 0px 0px 0px 2px #fff;\n}\n\n/* Container for floor image + floor name */\n.mapContainer {\n    position: absolute;\n    left: 0px;\n    top: 0px;\n    opacity: 1;\n}\n\n.mapImage {\n    position: absolute;\n    left: 0px;\n    top: 0px;\n}\n\n/* Display floor name at bottom right */\n.floorNameLabel {\n    position: absolute;\n    top: 0px;\n    right: 0px;\n    opacity: 0.99;\n    background-color: rgba(255, 255, 255, 0.7);\n}\n\n.floorText {\n    margin: 5px 5px 5px 5px;\n    color: black;\n}\n\n/* Div with text and progressbar - replaces the map image if map computation is running */\n.minimap-placeholder {\n    left: 0px;\n    top: 0px;\n    position: absolute;\n    background-color: rgba(255, 255, 255, 0.5);\n    opacity: 1;\n}\n\n.minimap-progressWidget {\n    transform: translate(0, -50%);\n    left: 0px;\n    top: 50%;\n    position: relative;\n    height: fit-content;\n    width: calc(100% - 60px);\n    margin-left: 30px;\n    margin-right: 30px;\n}\n\n.minimap-progressText {\n    color: black;\n    text-align: left;\n    position: relative;\n}\n\n.minimap-progress {\n    z-index: 10;\n    width: 100%;    \n}\n", ""]);

// exports


/***/ }),

/***/ "./node_modules/css-loader/index.js!./extensions/AEC/ui/ListPanel.css":
/*!*******************************************************************!*\
  !*** ./node_modules/css-loader!./extensions/AEC/ui/ListPanel.css ***!
  \*******************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false);
// imports


// module
exports.push([module.i, "\n.list-panel {\n    width: 260px;\n    min-width: 260px;\n    height: 260px;\n    min-height: 260px;\n    top: 180px;\n    left: 220px;\n    border-color:transparent;\n}\n\n.list-panel .itemList {\n    width: 100%;\n    display: flex;\n    flex-direction: column;\n}\n\n.list-panel .listItem {\n    display: flex;\n    justify-content: space-between;\n    text-align: left;\n    line-height: 35px;\n    background-color: rgba(0, 0, 0, 0.0);\n    border-style: none;\n\n    font-family: \"ArtifaktElement\", \"Helvetica Neue\", \"Segoe UI Semilight\", sans-serif;\n\n    padding: 0 15px;\n}\n\n.adsk-viewing-viewer.dark-theme .listItem {\n    color: #f3f7fb;\n}\n\n.adsk-viewing-viewer.light-theme .list-panel .listItem:hover {\n    background-color: rgba(10, 19, 28, 0.2);\n}\n\n.adsk-viewing-viewer.dark-theme .list-panel .listItem:hover {\n    background-color: #4a555b;\n}\n\n.list-panel .listItem:focus {\n    outline: none;\n}\n\n.list-panel .listItem.selected {\n    color: rgba(0, 191, 255, 1.0);\n    border-style: none;\n}\n\n.list-panel .listItem .textContainer {\n    -webkit-mask-image: linear-gradient(to left, transparent, black 1em);\n    mask-image: linear-gradient(to left, transparent, black 1em);\n    white-space: nowrap;\n    overflow: hidden;\n    width: 100%;\n}\n\n.list-panel .listItem .icon {\n    width: 24px;\n}\n\n.list-panel .listItem.selected .icon::before {\n    content: '\\2713';\n    margin-left: 8px;\n}\n\n.list-panel-item-warning {\n    background-image: url(\"\");\n    width:  24px;\n    height: 24px;\n    margin-left: auto;\n    margin-top: auto;\n    margin-bottom: auto;\n}\n", ""]);

// exports


/***/ }),

/***/ "./node_modules/css-loader/lib/css-base.js":
/*!*************************************************!*\
  !*** ./node_modules/css-loader/lib/css-base.js ***!
  \*************************************************/
/*! no static exports found */
/***/ (function(module, exports) {

/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
// css base code, injected by the css-loader
module.exports = function(useSourceMap) {
	var list = [];

	// return the list of modules as css string
	list.toString = function toString() {
		return this.map(function (item) {
			var content = cssWithMappingToString(item, useSourceMap);
			if(item[2]) {
				return "@media " + item[2] + "{" + content + "}";
			} else {
				return content;
			}
		}).join("");
	};

	// import a list of modules into the list
	list.i = function(modules, mediaQuery) {
		if(typeof modules === "string")
			modules = [[null, modules, ""]];
		var alreadyImportedModules = {};
		for(var i = 0; i < this.length; i++) {
			var id = this[i][0];
			if(typeof id === "number")
				alreadyImportedModules[id] = true;
		}
		for(i = 0; i < modules.length; i++) {
			var item = modules[i];
			// skip already imported module
			// this implementation is not 100% perfect for weird media query combinations
			//  when a module is imported multiple times with different media queries.
			//  I hope this will never occur (Hey this way we have smaller bundles)
			if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
				if(mediaQuery && !item[2]) {
					item[2] = mediaQuery;
				} else if(mediaQuery) {
					item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
				}
				list.push(item);
			}
		}
	};
	return list;
};

function cssWithMappingToString(item, useSourceMap) {
	var content = item[1] || '';
	var cssMapping = item[3];
	if (!cssMapping) {
		return content;
	}

	if (useSourceMap && typeof btoa === 'function') {
		var sourceMapping = toComment(cssMapping);
		var sourceURLs = cssMapping.sources.map(function (source) {
			return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'
		});

		return [content].concat(sourceURLs).concat([sourceMapping]).join('\n');
	}

	return [content].join('\n');
}

// Adapted from convert-source-map (MIT)
function toComment(sourceMap) {
	// eslint-disable-next-line no-undef
	var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));
	var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;

	return '/*# ' + data + ' */';
}


/***/ }),

/***/ "./node_modules/style-loader/lib/addStyles.js":
/*!****************************************************!*\
  !*** ./node_modules/style-loader/lib/addStyles.js ***!
  \****************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

var stylesInDom = {};

var	memoize = function (fn) {
	var memo;

	return function () {
		if (typeof memo === "undefined") memo = fn.apply(this, arguments);
		return memo;
	};
};

var isOldIE = memoize(function () {
	// Test for IE <= 9 as proposed by Browserhacks
	// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
	// Tests for existence of standard globals is to allow style-loader
	// to operate correctly into non-standard environments
	// @see https://github.com/webpack-contrib/style-loader/issues/177
	return window && document && document.all && !window.atob;
});

var getTarget = function (target, parent) {
  if (parent){
    return parent.querySelector(target);
  }
  return document.querySelector(target);
};

var getElement = (function (fn) {
	var memo = {};

	return function(target, parent) {
                // If passing function in options, then use it for resolve "head" element.
                // Useful for Shadow Root style i.e
                // {
                //   insertInto: function () { return document.querySelector("#foo").shadowRoot }
                // }
                if (typeof target === 'function') {
                        return target();
                }
                if (typeof memo[target] === "undefined") {
			var styleTarget = getTarget.call(this, target, parent);
			// Special case to return head of iframe instead of iframe itself
			if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
				try {
					// This will throw an exception if access to iframe is blocked
					// due to cross-origin restrictions
					styleTarget = styleTarget.contentDocument.head;
				} catch(e) {
					styleTarget = null;
				}
			}
			memo[target] = styleTarget;
		}
		return memo[target]
	};
})();

var singleton = null;
var	singletonCounter = 0;
var	stylesInsertedAtTop = [];

var	fixUrls = __webpack_require__(/*! ./urls */ "./node_modules/style-loader/lib/urls.js");

module.exports = function(list, options) {
	if (typeof DEBUG !== "undefined" && DEBUG) {
		if (typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
	}

	options = options || {};

	options.attrs = typeof options.attrs === "object" ? options.attrs : {};

	// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
	// tags it will allow on a page
	if (!options.singleton && typeof options.singleton !== "boolean") options.singleton = isOldIE();

	// By default, add <style> tags to the <head> element
        if (!options.insertInto) options.insertInto = "head";

	// By default, add <style> tags to the bottom of the target
	if (!options.insertAt) options.insertAt = "bottom";

	var styles = listToStyles(list, options);

	addStylesToDom(styles, options);

	return function update (newList) {
		var mayRemove = [];

		for (var i = 0; i < styles.length; i++) {
			var item = styles[i];
			var domStyle = stylesInDom[item.id];

			domStyle.refs--;
			mayRemove.push(domStyle);
		}

		if(newList) {
			var newStyles = listToStyles(newList, options);
			addStylesToDom(newStyles, options);
		}

		for (var i = 0; i < mayRemove.length; i++) {
			var domStyle = mayRemove[i];

			if(domStyle.refs === 0) {
				for (var j = 0; j < domStyle.parts.length; j++) domStyle.parts[j]();

				delete stylesInDom[domStyle.id];
			}
		}
	};
};

function addStylesToDom (styles, options) {
	for (var i = 0; i < styles.length; i++) {
		var item = styles[i];
		var domStyle = stylesInDom[item.id];

		if(domStyle) {
			domStyle.refs++;

			for(var j = 0; j < domStyle.parts.length; j++) {
				domStyle.parts[j](item.parts[j]);
			}

			for(; j < item.parts.length; j++) {
				domStyle.parts.push(addStyle(item.parts[j], options));
			}
		} else {
			var parts = [];

			for(var j = 0; j < item.parts.length; j++) {
				parts.push(addStyle(item.parts[j], options));
			}

			stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
		}
	}
}

function listToStyles (list, options) {
	var styles = [];
	var newStyles = {};

	for (var i = 0; i < list.length; i++) {
		var item = list[i];
		var id = options.base ? item[0] + options.base : item[0];
		var css = item[1];
		var media = item[2];
		var sourceMap = item[3];
		var part = {css: css, media: media, sourceMap: sourceMap};

		if(!newStyles[id]) styles.push(newStyles[id] = {id: id, parts: [part]});
		else newStyles[id].parts.push(part);
	}

	return styles;
}

function insertStyleElement (options, style) {
	var target = getElement(options.insertInto)

	if (!target) {
		throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");
	}

	var lastStyleElementInsertedAtTop = stylesInsertedAtTop[stylesInsertedAtTop.length - 1];

	if (options.insertAt === "top") {
		if (!lastStyleElementInsertedAtTop) {
			target.insertBefore(style, target.firstChild);
		} else if (lastStyleElementInsertedAtTop.nextSibling) {
			target.insertBefore(style, lastStyleElementInsertedAtTop.nextSibling);
		} else {
			target.appendChild(style);
		}
		stylesInsertedAtTop.push(style);
	} else if (options.insertAt === "bottom") {
		target.appendChild(style);
	} else if (typeof options.insertAt === "object" && options.insertAt.before) {
		var nextSibling = getElement(options.insertAt.before, target);
		target.insertBefore(style, nextSibling);
	} else {
		throw new Error("[Style Loader]\n\n Invalid value for parameter 'insertAt' ('options.insertAt') found.\n Must be 'top', 'bottom', or Object.\n (https://github.com/webpack-contrib/style-loader#insertat)\n");
	}
}

function removeStyleElement (style) {
	if (style.parentNode === null) return false;
	style.parentNode.removeChild(style);

	var idx = stylesInsertedAtTop.indexOf(style);
	if(idx >= 0) {
		stylesInsertedAtTop.splice(idx, 1);
	}
}

function createStyleElement (options) {
	var style = document.createElement("style");

	if(options.attrs.type === undefined) {
		options.attrs.type = "text/css";
	}

	if(options.attrs.nonce === undefined) {
		var nonce = getNonce();
		if (nonce) {
			options.attrs.nonce = nonce;
		}
	}

	addAttrs(style, options.attrs);
	insertStyleElement(options, style);

	return style;
}

function createLinkElement (options) {
	var link = document.createElement("link");

	if(options.attrs.type === undefined) {
		options.attrs.type = "text/css";
	}
	options.attrs.rel = "stylesheet";

	addAttrs(link, options.attrs);
	insertStyleElement(options, link);

	return link;
}

function addAttrs (el, attrs) {
	Object.keys(attrs).forEach(function (key) {
		el.setAttribute(key, attrs[key]);
	});
}

function getNonce() {
	if (false) {}

	return __webpack_require__.nc;
}

function addStyle (obj, options) {
	var style, update, remove, result;

	// If a transform function was defined, run it on the css
	if (options.transform && obj.css) {
	    result = typeof options.transform === 'function'
		 ? options.transform(obj.css) 
		 : options.transform.default(obj.css);

	    if (result) {
	    	// If transform returns a value, use that instead of the original css.
	    	// This allows running runtime transformations on the css.
	    	obj.css = result;
	    } else {
	    	// If the transform function returns a falsy value, don't add this css.
	    	// This allows conditional loading of css
	    	return function() {
	    		// noop
	    	};
	    }
	}

	if (options.singleton) {
		var styleIndex = singletonCounter++;

		style = singleton || (singleton = createStyleElement(options));

		update = applyToSingletonTag.bind(null, style, styleIndex, false);
		remove = applyToSingletonTag.bind(null, style, styleIndex, true);

	} else if (
		obj.sourceMap &&
		typeof URL === "function" &&
		typeof URL.createObjectURL === "function" &&
		typeof URL.revokeObjectURL === "function" &&
		typeof Blob === "function" &&
		typeof btoa === "function"
	) {
		style = createLinkElement(options);
		update = updateLink.bind(null, style, options);
		remove = function () {
			removeStyleElement(style);

			if(style.href) URL.revokeObjectURL(style.href);
		};
	} else {
		style = createStyleElement(options);
		update = applyToTag.bind(null, style);
		remove = function () {
			removeStyleElement(style);
		};
	}

	update(obj);

	return function updateStyle (newObj) {
		if (newObj) {
			if (
				newObj.css === obj.css &&
				newObj.media === obj.media &&
				newObj.sourceMap === obj.sourceMap
			) {
				return;
			}

			update(obj = newObj);
		} else {
			remove();
		}
	};
}

var replaceText = (function () {
	var textStore = [];

	return function (index, replacement) {
		textStore[index] = replacement;

		return textStore.filter(Boolean).join('\n');
	};
})();

function applyToSingletonTag (style, index, remove, obj) {
	var css = remove ? "" : obj.css;

	if (style.styleSheet) {
		style.styleSheet.cssText = replaceText(index, css);
	} else {
		var cssNode = document.createTextNode(css);
		var childNodes = style.childNodes;

		if (childNodes[index]) style.removeChild(childNodes[index]);

		if (childNodes.length) {
			style.insertBefore(cssNode, childNodes[index]);
		} else {
			style.appendChild(cssNode);
		}
	}
}

function applyToTag (style, obj) {
	var css = obj.css;
	var media = obj.media;

	if(media) {
		style.setAttribute("media", media)
	}

	if(style.styleSheet) {
		style.styleSheet.cssText = css;
	} else {
		while(style.firstChild) {
			style.removeChild(style.firstChild);
		}

		style.appendChild(document.createTextNode(css));
	}
}

function updateLink (link, options, obj) {
	var css = obj.css;
	var sourceMap = obj.sourceMap;

	/*
		If convertToAbsoluteUrls isn't defined, but sourcemaps are enabled
		and there is no publicPath defined then lets turn convertToAbsoluteUrls
		on by default.  Otherwise default to the convertToAbsoluteUrls option
		directly
	*/
	var autoFixUrls = options.convertToAbsoluteUrls === undefined && sourceMap;

	if (options.convertToAbsoluteUrls || autoFixUrls) {
		css = fixUrls(css);
	}

	if (sourceMap) {
		// http://stackoverflow.com/a/26603875
		css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
	}

	var blob = new Blob([css], { type: "text/css" });

	var oldSrc = link.href;

	link.href = URL.createObjectURL(blob);

	if(oldSrc) URL.revokeObjectURL(oldSrc);
}


/***/ }),

/***/ "./node_modules/style-loader/lib/urls.js":
/*!***********************************************!*\
  !*** ./node_modules/style-loader/lib/urls.js ***!
  \***********************************************/
/*! no static exports found */
/***/ (function(module, exports) {


/**
 * When source maps are enabled, `style-loader` uses a link element with a data-uri to
 * embed the css on the page. This breaks all relative urls because now they are relative to a
 * bundle instead of the current page.
 *
 * One solution is to only use full urls, but that may be impossible.
 *
 * Instead, this function "fixes" the relative urls to be absolute according to the current page location.
 *
 * A rudimentary test suite is located at `test/fixUrls.js` and can be run via the `npm test` command.
 *
 */

module.exports = function (css) {
  // get current location
  var location = typeof window !== "undefined" && window.location;

  if (!location) {
    throw new Error("fixUrls requires window.location");
  }

	// blank or null?
	if (!css || typeof css !== "string") {
	  return css;
  }

  var baseUrl = location.protocol + "//" + location.host;
  var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/");

	// convert each url(...)
	/*
	This regular expression is just a way to recursively match brackets within
	a string.

	 /url\s*\(  = Match on the word "url" with any whitespace after it and then a parens
	   (  = Start a capturing group
	     (?:  = Start a non-capturing group
	         [^)(]  = Match anything that isn't a parentheses
	         |  = OR
	         \(  = Match a start parentheses
	             (?:  = Start another non-capturing groups
	                 [^)(]+  = Match anything that isn't a parentheses
	                 |  = OR
	                 \(  = Match a start parentheses
	                     [^)(]*  = Match anything that isn't a parentheses
	                 \)  = Match a end parentheses
	             )  = End Group
              *\) = Match anything and then a close parens
          )  = Close non-capturing group
          *  = Match anything
       )  = Close capturing group
	 \)  = Match a close parens

	 /gi  = Get all matches, not the first.  Be case insensitive.
	 */
	var fixedCss = css.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi, function(fullMatch, origUrl) {
		// strip quotes (if they exist)
		var unquotedOrigUrl = origUrl
			.trim()
			.replace(/^"(.*)"$/, function(o, $1){ return $1; })
			.replace(/^'(.*)'$/, function(o, $1){ return $1; });

		// already a full url? no change
		if (/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/|\s*$)/i.test(unquotedOrigUrl)) {
		  return fullMatch;
		}

		// convert the url to a full url
		var newUrl;

		if (unquotedOrigUrl.indexOf("//") === 0) {
		  	//TODO: should we add protocol?
			newUrl = unquotedOrigUrl;
		} else if (unquotedOrigUrl.indexOf("/") === 0) {
			// path should be relative to the base url
			newUrl = baseUrl + unquotedOrigUrl; // already starts with '/'
		} else {
			// path should be relative to current directory
			newUrl = currentDir + unquotedOrigUrl.replace(/^\.\//, ""); // Strip leading './'
		}

		// send back the fixed url(...)
		return "url(" + JSON.stringify(newUrl) + ")";
	});

	// send back the fixed css
	return fixedCss;
};


/***/ })

/******/ });